summaryrefslogtreecommitdiff
path: root/test/misc
diff options
context:
space:
mode:
Diffstat (limited to 'test/misc')
-rw-r--r--test/misc/Makefile8
-rw-r--r--test/misc/Makefile.in42
-rw-r--r--test/misc/bug-glob1.c92
-rw-r--r--test/misc/bug-glob2.c300
-rw-r--r--test/misc/bug-readdir1.c37
-rw-r--r--test/misc/dirent.c39
-rw-r--r--test/misc/dirent64.c1
-rw-r--r--test/misc/fdopen.c52
-rw-r--r--test/misc/opendir-tst1.c95
-rw-r--r--test/misc/outb.c9
-rw-r--r--test/misc/popen.c47
-rw-r--r--test/misc/seek.c82
-rw-r--r--test/misc/sem.c45
-rw-r--r--test/misc/stdarg.c23
-rw-r--r--test/misc/tst-fnmatch.c443
-rw-r--r--test/misc/tst-fnmatch.input754
-rw-r--r--test/misc/tst-gnuglob.c446
-rw-r--r--test/misc/tst-inotify.c65
-rw-r--r--test/misc/tst-mkostemps.c159
-rw-r--r--test/misc/tst-nftw.c57
-rw-r--r--test/misc/tst-scandir.c23
-rw-r--r--test/misc/tst-seekdir.c79
-rw-r--r--test/misc/tst-statfs.c31
-rw-r--r--test/misc/tst-statvfs.c26
-rw-r--r--test/misc/tst-utmp.c423
-rw-r--r--test/misc/tst-utmpx.c2
26 files changed, 3380 insertions, 0 deletions
diff --git a/test/misc/Makefile b/test/misc/Makefile
new file mode 100644
index 0000000..09fa233
--- /dev/null
+++ b/test/misc/Makefile
@@ -0,0 +1,8 @@
+# uClibc misc 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/misc/Makefile.in b/test/misc/Makefile.in
new file mode 100644
index 0000000..7d7bb10
--- /dev/null
+++ b/test/misc/Makefile.in
@@ -0,0 +1,42 @@
+# uClibc misc tests
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+
+TESTS_DISABLED := outb tst-fnmatch bug-glob1 tst-gnuglob
+
+ifeq ($(TARGET_avr32),y)
+TESTS_DISABLED += tst-inotify
+endif
+
+ifeq ($(UCLIBC_HAS_LFS),)
+TESTS_DISABLED += dirent64
+TESTS_DISABLED += tst-statfs # assuming host has LFS on
+endif
+CFLAGS_dirent64 := -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
+
+ifeq ($(UCLIBC_LINUX_SPECIFIC),)
+TESTS_DISABLED += tst-inotify
+endif
+
+ifeq ($(UCLIBC_HAS_GLOB),)
+TESTS_DISABLED += bug-glob2
+endif
+
+ifeq ($(UCLIBC_HAS_UTMPX),)
+TESTS_DISABLED += tst-utmpx
+endif
+
+ifeq ($(UCLIBC_HAS_UTMP),)
+TESTS_DISABLED += tst-utmp
+endif
+
+DODIFF_dirent := 1
+DODIFF_dirent64 := 1
+DODIFF_tst-statfs := 1
+DODIFF_tst-statvfs := 1
+
+OPTS_bug-glob1 := $(PWD)
+OPTS_tst-fnmatch := < tst-fnmatch.input
+
+MNTENTS = / /sys /proc /dev
+OPTS_tst-statfs := $(MNTENTS)
+OPTS_tst-statvfs := $(MNTENTS)
diff --git a/test/misc/bug-glob1.c b/test/misc/bug-glob1.c
new file mode 100644
index 0000000..276983a
--- /dev/null
+++ b/test/misc/bug-glob1.c
@@ -0,0 +1,92 @@
+/* Test case for globbing dangling symlink. By Ulrich Drepper. */
+#include <errno.h>
+#include <error.h>
+#include <glob.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+
+static void prepare (int argc, char *argv[]);
+#define PREPARE prepare
+static int do_test (void);
+#define TEST_FUNCTION do_test ()
+
+#include "../test-skeleton.c"
+
+
+static char *fname;
+
+static void
+prepare (int argc, char *argv[])
+{
+ if (argc < 2)
+ error (EXIT_FAILURE, 0, "missing argument");
+
+ size_t len = strlen (argv[1]);
+ static const char ext[] = "globXXXXXX";
+ fname = malloc (len + sizeof (ext));
+ if (fname == NULL)
+ error (EXIT_FAILURE, errno, "cannot create temp file");
+ again:
+ strcpy (stpcpy (fname, argv[1]), ext);
+
+/* fname = mktemp (fname); */
+ close(mkstemp(fname));
+ unlink(fname);
+
+ if (fname == NULL || *fname == '\0')
+ error (EXIT_FAILURE, errno, "cannot create temp file name");
+ if (symlink ("bug-glob1-does-not-exist", fname) != 0)
+ {
+ if (errno == EEXIST)
+ goto again;
+
+ error (EXIT_FAILURE, errno, "cannot create symlink");
+ }
+ add_temp_file (fname);
+}
+
+
+static int
+do_test (void)
+{
+ glob_t gl;
+ int retval = 0;
+ int e;
+
+ e = glob (fname, 0, NULL, &gl);
+ if (e == 0)
+ {
+ printf ("glob(\"%s\") succeeded when it should not have\n", fname);
+ retval = 1;
+ }
+ globfree (&gl);
+
+ size_t fnamelen = strlen (fname);
+ char buf[fnamelen + 2];
+
+ strcpy (buf, fname);
+ buf[fnamelen - 1] = '?';
+ e = glob (buf, 0, NULL, &gl);
+ if (e == 0)
+ {
+ printf ("glob(\"%s\") succeeded when it should not have\n", buf);
+ retval = 1;
+ }
+ globfree (&gl);
+
+ strcpy (buf, fname);
+ buf[fnamelen] = '*';
+ buf[fnamelen + 1] = '\0';
+ e = glob (buf, 0, NULL, &gl);
+ if (e == 0)
+ {
+ printf ("glob(\"%s\") succeeded when it should not have\n", buf);
+ retval = 1;
+ }
+ globfree (&gl);
+
+ return retval;
+}
diff --git a/test/misc/bug-glob2.c b/test/misc/bug-glob2.c
new file mode 100644
index 0000000..069891b
--- /dev/null
+++ b/test/misc/bug-glob2.c
@@ -0,0 +1,300 @@
+/* Test glob memory management.
+ for the filesystem access functions.
+ Copyright (C) 2001, 2002, 2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ 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 <dirent.h>
+#include <glob.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+
+// #define DEBUG
+#ifdef DEBUG
+# define PRINTF(fmt, args...) \
+ do \
+ { \
+ int save_errno = errno; \
+ printf (fmt, ##args); \
+ errno = save_errno; \
+ } while (0)
+#else
+# define PRINTF(fmt, args...)
+#endif
+
+
+#ifdef GLOB_ALTDIRFUNC
+static struct
+{
+ const char *name;
+ int level;
+ int type;
+ mode_t mode;
+} filesystem[] =
+{
+ { ".", 1, DT_DIR, 0755 },
+ { "..", 1, DT_DIR, 0755 },
+ { "dir", 1, DT_DIR, 0755 },
+ { ".", 2, DT_DIR, 0755 },
+ { "..", 2, DT_DIR, 0755 },
+ { "readable", 2, DT_DIR, 0755 },
+ { ".", 3, DT_DIR, 0755 },
+ { "..", 3, DT_DIR, 0755 },
+ { "a", 3, DT_REG, 0644 },
+ { "unreadable", 2, DT_DIR, 0111 },
+ { ".", 3, DT_DIR, 0111 },
+ { "..", 3, DT_DIR, 0755 },
+ { "a", 3, DT_REG, 0644 },
+ { "zz-readable", 2, DT_DIR, 0755 },
+ { ".", 3, DT_DIR, 0755 },
+ { "..", 3, DT_DIR, 0755 },
+ { "a", 3, DT_REG, 0644 }
+};
+#define nfiles (sizeof (filesystem) / sizeof (filesystem[0]))
+
+
+typedef struct
+{
+ int level;
+ int idx;
+ struct dirent d;
+ char room_for_dirent[NAME_MAX];
+} my_DIR;
+
+
+static long int
+find_file (const char *s)
+{
+ int level = 1;
+ long int idx = 0;
+
+ if (strcmp (s, ".") == 0)
+ return 0;
+
+ if (s[0] == '.' && s[1] == '/')
+ s += 2;
+
+ while (*s != '\0')
+ {
+ char *endp = strchrnul (s, '/');
+
+ PRINTF ("looking for %.*s, level %d\n", (int) (endp - s), s, level);
+
+ while (idx < nfiles && filesystem[idx].level >= level)
+ {
+ if (filesystem[idx].level == level
+ && memcmp (s, filesystem[idx].name, endp - s) == 0
+ && filesystem[idx].name[endp - s] == '\0')
+ break;
+ ++idx;
+ }
+
+ if (idx == nfiles || filesystem[idx].level < level)
+ {
+ errno = ENOENT;
+ return -1;
+ }
+
+ if (*endp == '\0')
+ return idx + 1;
+
+ if (filesystem[idx].type != DT_DIR
+ && (idx + 1 >= nfiles
+ || filesystem[idx].level >= filesystem[idx + 1].level))
+ {
+ errno = ENOTDIR;
+ return -1;
+ }
+
+ ++idx;
+
+ s = endp + 1;
+ ++level;
+ }
+
+ errno = ENOENT;
+ return -1;
+}
+
+
+static void *
+my_opendir (const char *s)
+{
+ long int idx = find_file (s);
+ my_DIR *dir;
+
+ if (idx == -1)
+ {
+ PRINTF ("my_opendir(\"%s\") == NULL (%m)\n", s);
+ return NULL;
+ }
+
+ if ((filesystem[idx].mode & 0400) == 0)
+ {
+ errno = EACCES;
+ PRINTF ("my_opendir(\"%s\") == NULL (%m)\n", s);
+ return NULL;
+ }
+
+ dir = (my_DIR *) malloc (sizeof (my_DIR));
+ if (dir == NULL)
+ {
+ printf ("cannot allocate directory handle: %m\n");
+ exit (EXIT_FAILURE);
+ }
+
+ dir->level = filesystem[idx].level;
+ dir->idx = idx;
+
+ PRINTF ("my_opendir(\"%s\") == { level: %d, idx: %ld }\n",
+ s, filesystem[idx].level, idx);
+
+ return dir;
+}
+
+
+static struct dirent *
+my_readdir (void *gdir)
+{
+ my_DIR *dir = gdir;
+
+ if (dir->idx == -1)
+ {
+ PRINTF ("my_readdir ({ level: %d, idx: %ld }) = NULL\n",
+ dir->level, (long int) dir->idx);
+ return NULL;
+ }
+
+ while (dir->idx < nfiles && filesystem[dir->idx].level > dir->level)
+ ++dir->idx;
+
+ if (dir->idx == nfiles || filesystem[dir->idx].level < dir->level)
+ {
+ dir->idx = -1;
+ PRINTF ("my_readdir ({ level: %d, idx: %ld }) = NULL\n",
+ dir->level, (long int) dir->idx);
+ return NULL;
+ }
+
+ dir->d.d_ino = dir->idx;
+
+#ifdef _DIRENT_HAVE_D_TYPE
+ dir->d.d_type = filesystem[dir->idx].type;
+#endif
+
+ strcpy (dir->d.d_name, filesystem[dir->idx].name);
+
+#ifdef _DIRENT_HAVE_D_TYPE
+ PRINTF ("my_readdir ({ level: %d, idx: %ld }) = { d_ino: %ld, d_type: %d, d_name: \"%s\" }\n",
+ dir->level, (long int) dir->idx, dir->d.d_ino, dir->d.d_type,
+ dir->d.d_name);
+#else
+ PRINTF ("my_readdir ({ level: %d, idx: %ld }) = { d_ino: %ld, d_name: \"%s\" }\n",
+ dir->level, (long int) dir->idx, dir->d.d_ino,
+ dir->d.d_name);
+#endif
+
+ ++dir->idx;
+
+ return &dir->d;
+}
+
+
+static void
+my_closedir (void *dir)
+{
+ PRINTF ("my_closedir ()\n");
+ free (dir);
+}
+
+
+/* We use this function for lstat as well since we don't have any. */
+static int
+my_stat (const char *name, struct stat *st)
+{
+ long int idx = find_file (name);
+
+ if (idx == -1)
+ {
+ PRINTF ("my_stat (\"%s\", ...) = -1 (%m)\n", name);
+ return -1;
+ }
+
+ memset (st, '\0', sizeof (*st));
+
+ if (filesystem[idx].type == DT_UNKNOWN)
+ st->st_mode = DTTOIF (idx + 1 < nfiles
+ && filesystem[idx].level < filesystem[idx + 1].level
+ ? DT_DIR : DT_REG) | filesystem[idx].mode;
+ else
+ st->st_mode = DTTOIF (filesystem[idx].type) | filesystem[idx].mode;
+
+ PRINTF ("my_stat (\"%s\", { st_mode: %o }) = 0\n", name, st->st_mode);
+
+ return 0;
+}
+
+
+static void
+init_glob_altdirfuncs (glob_t *pglob)
+{
+ pglob->gl_closedir = my_closedir;
+ pglob->gl_readdir = my_readdir;
+ pglob->gl_opendir = my_opendir;
+ pglob->gl_lstat = my_stat;
+ pglob->gl_stat = my_stat;
+}
+
+
+static int
+do_test (void)
+{
+ glob_t gl;
+ memset (&gl, 0, sizeof (gl));
+ init_glob_altdirfuncs (&gl);
+
+ if (glob ("dir/*able/*", GLOB_ERR | GLOB_ALTDIRFUNC, NULL, &gl)
+ != GLOB_ABORTED)
+ {
+ puts ("glob did not fail with GLOB_ABORTED");
+ exit (EXIT_FAILURE);
+ }
+
+ globfree (&gl);
+
+ memset (&gl, 0, sizeof (gl));
+ init_glob_altdirfuncs (&gl);
+
+ gl.gl_offs = 3;
+ if (glob ("dir2/*", GLOB_DOOFFS, NULL, &gl) != GLOB_NOMATCH)
+ {
+ puts ("glob did not fail with GLOB_NOMATCH");
+ exit (EXIT_FAILURE);
+ }
+
+ globfree (&gl);
+
+ return 0;
+}
+#else
+static int do_test (void) { return 0; }
+#endif
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/misc/bug-readdir1.c b/test/misc/bug-readdir1.c
new file mode 100644
index 0000000..a8594a8
--- /dev/null
+++ b/test/misc/bug-readdir1.c
@@ -0,0 +1,37 @@
+#include <dirent.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+
+int
+main (void)
+{
+ DIR *dirp;
+ struct dirent* ent;
+
+ /* open a dir stream */
+ dirp = opendir ("/tmp");
+ if (dirp == NULL)
+ {
+ if (errno == ENOENT)
+ exit (0);
+
+ perror ("opendir");
+ exit (1);
+ }
+
+ /* close the directory file descriptor, making it invalid */
+ if (close (dirfd (dirp)) != 0)
+ {
+ puts ("could not close directory file descriptor");
+ /* This is not an error. It is not guaranteed this is possible. */
+ return 0;
+ }
+
+ ent = readdir (dirp);
+
+ return ent != NULL || errno != EBADF;
+}
diff --git a/test/misc/dirent.c b/test/misc/dirent.c
new file mode 100644
index 0000000..491e3cf
--- /dev/null
+++ b/test/misc/dirent.c
@@ -0,0 +1,39 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
+
+#define _DTIFY(DT) [DT] #DT
+const char * const types[] = {
+ _DTIFY(DT_UNKNOWN),
+ _DTIFY(DT_FIFO),
+ _DTIFY(DT_CHR),
+ _DTIFY(DT_DIR),
+ _DTIFY(DT_BLK),
+ _DTIFY(DT_REG),
+ _DTIFY(DT_LNK),
+ _DTIFY(DT_SOCK),
+ _DTIFY(DT_WHT)
+};
+
+int main(int argc, char *argv[])
+{
+ DIR *dirh;
+ struct dirent *de;
+ const char *mydir = (argc == 1 ? "/" : argv[1]);
+
+ if ((dirh = opendir(mydir)) == NULL) {
+ perror("opendir");
+ return 1;
+ }
+
+ printf("readdir() says:\n");
+ while ((de = readdir(dirh)) != NULL)
+ printf("\tdir entry %s: %s\n", types[de->d_type], de->d_name);
+
+ closedir(dirh);
+
+ return 0;
+}
diff --git a/test/misc/dirent64.c b/test/misc/dirent64.c
new file mode 100644
index 0000000..26455ab
--- /dev/null
+++ b/test/misc/dirent64.c
@@ -0,0 +1 @@
+#include "dirent.c"
diff --git a/test/misc/fdopen.c b/test/misc/fdopen.c
new file mode 100644
index 0000000..97e66de
--- /dev/null
+++ b/test/misc/fdopen.c
@@ -0,0 +1,52 @@
+/* Test for fdopen bugs. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#define assert(x) \
+ if (!(x)) \
+ { \
+ fputs ("test failed: " #x "\n", stderr); \
+ retval = 1; \
+ goto the_end; \
+ }
+
+int
+main (int argc, char *argv[])
+{
+ char name[256];
+ FILE *fp = NULL;
+ int retval = 0;
+ int fd;
+
+ /* hack to get a tempfile name w/out using tmpname()
+ * as that func causes a link time warning */
+ sprintf(name, "%s-uClibc-test.XXXXXX", __FILE__);
+ fd = mkstemp(name);
+ close(fd);
+
+ fp = fopen (name, "w");
+ assert (fp != NULL)
+ assert (fputs ("foobar and baz", fp) > 0);
+ assert (fclose (fp) == 0);
+ fp = NULL;
+
+ fd = open (name, O_RDWR|O_CREAT, 0660);
+ assert (fd != -1);
+ assert (lseek (fd, 5, SEEK_SET) == 5);
+
+ fp = fdopen (fd, "a");
+ assert (fp != NULL);
+ /* SuSv3 says that doing a fdopen() does not reset the file position,
+ * thus the '5' here is correct, not '14'. */
+ assert (ftell (fp) == 5);
+
+the_end:
+ if (fp != NULL)
+ assert (fclose (fp) == 0);
+ unlink (name);
+
+ return retval;
+}
diff --git a/test/misc/opendir-tst1.c b/test/misc/opendir-tst1.c
new file mode 100644
index 0000000..ffd785f
--- /dev/null
+++ b/test/misc/opendir-tst1.c
@@ -0,0 +1,95 @@
+/* Copyright (C) 1998, 2000 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 <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+/* Name of the FIFO. */
+char tmpname[] = "fifoXXXXXX";
+
+
+/* Do the real work. */
+static int
+real_test (void)
+{
+ DIR *dirp;
+
+ /* This should not block for an FIFO. */
+ dirp = opendir (tmpname);
+
+ /* Successful. */
+ if (dirp != NULL)
+ {
+ /* Oh, oh, how can this work? */
+ fputs ("`opendir' succeeded on a FIFO???\n", stdout);
+ closedir (dirp);
+ return 1;
+ }
+
+ if (errno != ENOTDIR)
+ {
+ fprintf (stdout, "`opendir' return error `%s' instead of `%s'\n",
+ strerror (errno), strerror (ENOTDIR));
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int
+do_test (int argc, char *argv[])
+{
+ int retval;
+
+ retval = mkstemp(tmpname);
+ close(retval);
+ unlink(tmpname);
+
+ /* Try to generate a FIFO. */
+ if (mknod (tmpname, 0600 | S_IFIFO, 0) < 0)
+ {
+ perror ("mknod");
+ /* We cannot make this an error. */
+ return 0;
+ }
+
+ retval = real_test ();
+
+ remove (tmpname);
+
+ return retval;
+}
+
+
+static void
+do_cleanup (void)
+{
+ remove (tmpname);
+}
+#define CLEANUP_HANDLER do_cleanup ()
+
+
+/* Include the test skeleton. */
+#include "../test-skeleton.c"
diff --git a/test/misc/outb.c b/test/misc/outb.c
new file mode 100644
index 0000000..bbe18ea
--- /dev/null
+++ b/test/misc/outb.c
@@ -0,0 +1,9 @@
+#include <sys/io.h>
+
+int main(void)
+{
+ ioperm(0x340,0x342,1);
+ outb(0x340,0x0);
+ exit(0);
+}
+
diff --git a/test/misc/popen.c b/test/misc/popen.c
new file mode 100644
index 0000000..868b70e
--- /dev/null
+++ b/test/misc/popen.c
@@ -0,0 +1,47 @@
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+
+#define TEST(r, f, x, m) ( \
+((r) = (f)) == (x) || \
+(printf(__FILE__ ":%d: %s failed (" m ")\n", __LINE__, #f, r, x), err++, 0) )
+
+#define TEST_E(f) ( (errno = 0), (f) || \
+(printf(__FILE__ ":%d: %s failed (errno = %d)\n", __LINE__, #f, errno), err++, 0) )
+
+#define TEST_S(s, x, m) ( \
+!strcmp((s),(x)) || \
+(printf(__FILE__ ":%d: [%s] != [%s] (%s)\n", __LINE__, s, x, m), err++, 0) )
+
+static sig_atomic_t got_sig;
+
+static void handler(int sig)
+{
+ got_sig = 1;
+}
+
+int main(void)
+{
+ int i;
+ char foo[6];
+ char cmd[64];
+ int err = 0;
+ FILE *f;
+
+ TEST_E(f = popen("echo hello", "r"));
+ TEST_E(fgets(foo, sizeof foo, f));
+ TEST_S(foo, "hello", "child process did not say hello");
+ TEST(i, pclose(f), 0, "exit status %04x != %04x");
+
+ signal(SIGUSR1, handler);
+ snprintf(cmd, sizeof cmd, "read a ; test \"x$a\" = xhello && kill -USR1 %d", getpid());
+ TEST_E(f = popen(cmd, "w"));
+ TEST_E(fputs("hello", f) >= 0);
+ TEST(i, pclose(f), 0, "exit status %04x != %04x");
+ signal(SIGUSR1, SIG_DFL);
+ TEST(i, got_sig, 1, "child process did not send signal (%i!=%i)");
+
+ return err;
+}
diff --git a/test/misc/seek.c b/test/misc/seek.c
new file mode 100644
index 0000000..c5edb94
--- /dev/null
+++ b/test/misc/seek.c
@@ -0,0 +1,82 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <assert.h>
+
+#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(*arr))
+
+int main(void)
+{
+ struct {
+ off_t offset;
+ int whence;
+ } tests[] = {
+ { 0x00, SEEK_SET },
+ { 0x01, SEEK_SET },
+ { 0xFF, SEEK_SET }
+ };
+ char buf[2000];
+ off_t ret;
+ int i, fd;
+ FILE *fp;
+ int tmp;
+
+ fd = open("lseek.out", O_RDWR|O_CREAT, 0600);
+ if (fd == -1) {
+ perror("open(lseek.out) failed");
+ return 1;
+ }
+ unlink("lseek.out");
+ fp = fdopen(fd, "rw");
+ if (fp == NULL) {
+ perror("fopen(lseek.out) failed");
+ return 1;
+ }
+
+ memset(buf, 0xAB, sizeof(buf));
+ ret = write(fd, buf, sizeof(buf));
+ if (ret != sizeof(buf)) {
+ fprintf(stderr, "write() failed to write %zi bytes (wrote %li): ", sizeof(buf), (long)ret);
+ perror("");
+ return 1;
+ }
+
+ tmp = fseeko(fp, 1024, SEEK_SET);
+ assert(tmp == 0);
+ tmp = fseeko(fp, (off_t)-16, SEEK_CUR);
+ assert(tmp == 0);
+ ret = ftell(fp);
+ if (ret != (1024-16)) {
+ fprintf(stderr, "ftell() failed, we wanted pos %i but got %li: ", (1024-16), (long)ret);
+ perror("");
+ return 1;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(tests); ++i) {
+ ret = lseek(fd, tests[i].offset, tests[i].whence);
+ if (ret != tests[i].offset) {
+ fprintf(stderr, "lseek(%li,%i) failed (wanted %li, got %li): ", (long)tests[i].offset,
+ tests[i].whence, (long)tests[i].offset, (long)ret);
+ perror("");
+ return 1;
+ }
+ ret = fseek(fp, tests[i].offset, tests[i].whence);
+ if (ret != 0) {
+ fprintf(stderr, "fseek(%li,%i) failed (wanted 0, got %li): ", (long)tests[i].offset,
+ tests[i].whence, (long)ret);
+ perror("");
+ return 1;
+ }
+ }
+
+ fclose(fp);
+ close(fd);
+
+ printf("Success!\n");
+
+ return 0;
+}
diff --git a/test/misc/sem.c b/test/misc/sem.c
new file mode 100644
index 0000000..62a59b1
--- /dev/null
+++ b/test/misc/sem.c
@@ -0,0 +1,45 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+
+int main(void)
+{
+ int k, r;
+ union semun {
+ int val;
+ struct semid_ds *buf;
+ unsigned short int *array;
+ struct seminfo *__buf;
+ } sd;
+ struct semid_ds sd_buf;
+
+ k = semget(IPC_PRIVATE, 10, IPC_CREAT | 0666 );
+ printf("semget(IPC_CREAT) = %d\n", k);
+
+ if (k < 0) {
+ fprintf(stderr, "semget failed: %s\n", strerror(errno));
+ return 1;
+ }
+
+ sd.buf = &sd_buf;
+ r = semctl(k, 0, IPC_STAT, sd);
+ printf("semctl(k) = %d\n", r);
+
+ if (r < 0) {
+ perror("semctl IPC_STAT failed");
+ return 1;
+ }
+
+ printf("sem_nsems = %lu\n", sd_buf.sem_nsems);
+ if (sd_buf.sem_nsems != 10) {
+ fprintf(stderr, "failed: incorrect sem_nsems!\n");
+ return 1;
+ }
+
+ printf("succeeded\n");
+
+ return 0;
+}
diff --git a/test/misc/stdarg.c b/test/misc/stdarg.c
new file mode 100644
index 0000000..1566e0c
--- /dev/null
+++ b/test/misc/stdarg.c
@@ -0,0 +1,23 @@
+/* copied from rsync */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <stdarg.h>
+static int foo(const char *format, ...)
+{
+ va_list ap;
+ size_t len;
+ char buf[5];
+
+ va_start(ap, format);
+ len = vsnprintf(0, 0, format, ap);
+ va_end(ap);
+ if (len != 5) return(1);
+
+ if (snprintf(buf, 3, "hello") != 5 || strcmp(buf, "he") != 0) return(1);
+
+ return(0);
+}
+int main(void) { return foo("hello"); }
diff --git a/test/misc/tst-fnmatch.c b/test/misc/tst-fnmatch.c
new file mode 100644
index 0000000..e7d5324
--- /dev/null
+++ b/test/misc/tst-fnmatch.c
@@ -0,0 +1,443 @@
+/* Tests for fnmatch function.
+ Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ 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 <error.h>
+#include <fnmatch.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+
+
+static char *next_input (char **line, int first, int last);
+static int convert_flags (const char *str);
+static char *flag_output (int flags);
+static char *escape (const char *str, size_t *reslenp, char **resbuf);
+
+
+int str_isalpha(const char *str)
+{
+ size_t i = strlen(str);
+ while (i--)
+ if (isascii(str[i]) == 0)
+ return 0;
+ return 1;
+}
+int str_has_funk(const char *str, const char x)
+{
+ size_t i, max = strlen(str);
+ for (i=0; i+1<max; ++i)
+ if (str[i] == '[' && str[i+1] == x)
+ return 1;
+ return 0;
+}
+
+
+int
+main (void)
+{
+ char *linebuf = NULL;
+ size_t linebuflen = 0;
+ int ntests = 0;
+ int nfailed = 0;
+ int nskipped = 0;
+ char *escinput = NULL;
+ size_t escinputlen = 0;
+ char *escpattern = NULL;
+ size_t escpatternlen = 0;
+ int nr = 0;
+
+ /* Read lines from stdin with the following format:
+
+ locale input-string match-string flags result
+
+ where `result' is either 0 or 1. If the first character of a
+ string is '"' we read until the next '"' and handled escaped '"'. */
+ while (! feof (stdin))
+ {
+ ssize_t n = getline (&linebuf, &linebuflen, stdin);
+ char *cp;
+ const char *locale;
+ const char *input;
+ const char *pattern;
+ const char *result_str;
+ int result;
+ const char *flags;
+ int flags_val;
+ int fnmres;
+ char numbuf[24];
+
+ if (n == -1)
+ break;
+
+ if (n == 0)
+ /* Maybe an empty line. */
+ continue;
+
+ /* Skip over all leading white spaces. */
+ cp = linebuf;
+
+ locale = next_input (&cp, 1, 0);
+ if (locale == NULL)
+ continue;
+
+ input = next_input (&cp, 0, 0);
+ if (input == NULL)
+ continue;
+
+ pattern = next_input (&cp, 0, 0);
+ if (pattern == NULL)
+ continue;
+
+ result_str = next_input (&cp, 0, 0);
+ if (result_str == NULL)
+ continue;
+
+ if (strcmp (result_str, "0") == 0)
+ result = 0;
+ else if (strcasecmp (result_str, "NOMATCH") == 0)
+ result = FNM_NOMATCH;
+ else
+ {
+ char *endp;
+ result = strtol (result_str, &endp, 0);
+ if (*endp != '\0')
+ continue;
+ }
+
+ flags = next_input (&cp, 0, 1);
+ if (flags == NULL)
+ /* We allow the flags missing. */
+ flags = "";
+
+ /* Convert the text describing the flags in a numeric value. */
+ flags_val = convert_flags (flags);
+ if (flags_val == -1)
+ /* Something went wrong. */
+ continue;
+
+ /* Now run the actual test. */
+ ++ntests;
+
+#ifdef __UCLIBC_HAS_XLOCALE__
+ if (setlocale (LC_COLLATE, locale) == NULL
+ || setlocale (LC_CTYPE, locale) == NULL)
+ {
+ puts ("*** Cannot set locale");
+ ++nfailed;
+ continue;
+ }
+#else
+ /* skip non-ascii strings */
+ if (!str_isalpha(pattern) || !str_isalpha(input))
+ {
+ ++nskipped;
+ printf("%3d: fnmatch (\"%s\", \"%s\"): SKIP multibyte test (requires locale support)\n", ++nr, pattern, input);
+ continue;
+ }
+ /* skip collating symbols */
+ if (str_has_funk(pattern, '.') || str_has_funk(input, '.'))
+ {
+ ++nskipped;
+ printf("%3d: fnmatch (\"%s\", \"%s\"): SKIP collating symbol test (requires locale support)\n", ++nr, pattern, input);
+ continue;
+ }
+ /* skip equivalence class expressions */
+ if (str_has_funk(pattern, '=') || str_has_funk(input, '='))
+ {
+ ++nskipped;
+ printf("%3d: fnmatch (\"%s\", \"%s\"): SKIP equivalence class test (requires locale support)\n", ++nr, pattern, input);
+ continue;
+ }
+#endif
+
+ fnmres = fnmatch (pattern, input, flags_val);
+
+ printf ("%3d: fnmatch (\"%s\", \"%s\", %s) = %s%c",
+ ++nr,
+ escape (pattern, &escpatternlen, &escpattern),
+ escape (input, &escinputlen, &escinput),
+ flag_output (flags_val),
+ (fnmres == 0
+ ? "0" : (fnmres == FNM_NOMATCH
+ ? "FNM_NOMATCH"
+ : (sprintf (numbuf, "%d", fnmres), numbuf))),
+ (fnmres != 0) != (result != 0) ? ' ' : '\n');
+
+ if ((fnmres != 0) != (result != 0))
+ {
+ printf ("(FAIL, expected %s) ***\n",
+ result == 0
+ ? "0" : (result == FNM_NOMATCH
+ ? "FNM_NOMATCH"
+ : (sprintf (numbuf, "%d", result), numbuf)));
+ ++nfailed;
+ }
+ }
+
+ printf ("=====================\n%3d tests, %3d failed, %3d skipped\n", ntests, nfailed, nskipped);
+
+ free (escpattern);
+ free (escinput);
+ free (linebuf);
+
+ return nfailed != 0;
+}
+
+
+static char *
+next_input (char **line, int first, int last)
+{
+ char *cp = *line;
+ char *result;
+
+ while (*cp == ' ' || *cp == '\t')
+ ++cp;
+
+ /* We allow comment lines starting with '#'. */
+ if (first && *cp == '#')
+ return NULL;
+
+ if (*cp == '"')
+ {
+ char *wp;
+
+ result = ++cp;
+ wp = cp;
+
+ while (*cp != '"' && *cp != '\0' && *cp != '\n')
+ if (*cp == '\\')
+ {
+ if (cp[1] == '\n' || cp[1] == '\0')
+ return NULL;
+
+ ++cp;
+ if (*cp == 't')
+ *wp++ = '\t';
+ else if (*cp == 'n')
+ *wp++ = '\n';
+ else
+ *wp++ = *cp;
+
+ ++cp;
+ }
+ else
+ *wp++ = *cp++;
+
+ if (*cp != '"')
+ return NULL;
+
+ if (wp != cp)
+ *wp = '\0';
+ }
+ else
+ {
+ result = cp;
+ while (*cp != '\0' && *cp != '\n' && *cp != ' ' && *cp != '\t')
+ ++cp;
+
+ if (cp == result && ! last)
+ /* Premature end of line. */
+ return NULL;
+ }
+
+ /* Terminate and skip over the next white spaces. */
+ *cp++ = '\0';
+
+ *line = cp;
+ return result;
+}
+
+
+static int
+convert_flags (const char *str)
+{
+ int result = 0;
+
+ while (*str != '\0')
+ {
+ int len;
+
+ if (strncasecmp (str, "PATHNAME", 8) == 0
+ && (str[8] == '|' || str[8] == '\0'))
+ {
+ result |= FNM_PATHNAME;
+ len = 8;
+ }
+ else if (strncasecmp (str, "NOESCAPE", 8) == 0
+ && (str[8] == '|' || str[8] == '\0'))
+ {
+ result |= FNM_NOESCAPE;
+ len = 8;
+ }
+ else if (strncasecmp (str, "PERIOD", 6) == 0
+ && (str[6] == '|' || str[6] == '\0'))
+ {
+ result |= FNM_PERIOD;
+ len = 6;
+ }
+#ifdef FNM_LEADING_DIR
+ else if (strncasecmp (str, "LEADING_DIR", 11) == 0
+ && (str[11] == '|' || str[11] == '\0'))
+ {
+ result |= FNM_LEADING_DIR;
+ len = 11;
+ }
+#endif
+#ifdef FNM_CASEFOLD
+ else if (strncasecmp (str, "CASEFOLD", 8) == 0
+ && (str[8] == '|' || str[8] == '\0'))
+ {
+ result |= FNM_CASEFOLD;
+ len = 8;
+ }
+#endif
+#ifdef FNM_EXTMATCH
+ else if (strncasecmp (str, "EXTMATCH", 8) == 0
+ && (str[8] == '|' || str[8] == '\0'))
+ {
+ result |= FNM_EXTMATCH;
+ len = 8;
+ }
+#endif
+ else
+ return -1;
+
+ str += len;
+ if (*str != '\0')
+ ++str;
+ }
+
+ return result;
+}
+
+
+static char *
+flag_output (int flags)
+{
+ static char buf[100];
+ int first = 1;
+ char *cp = buf;
+
+ if (flags & FNM_PATHNAME)
+ {
+ cp = stpcpy (cp, "FNM_PATHNAME");
+ first = 0;
+ }
+ if (flags & FNM_NOESCAPE)
+ {
+ if (! first)
+ *cp++ = '|';
+ cp = stpcpy (cp, "FNM_NOESCAPE");
+ first = 0;
+ }
+ if (flags & FNM_PERIOD)
+ {
+ if (! first)
+ *cp++ = '|';
+ cp = stpcpy (cp, "FNM_PERIOD");
+ first = 0;
+ }
+#ifdef FNM_LEADING_DIR
+ if (flags & FNM_LEADING_DIR)
+ {
+ if (! first)
+ *cp++ = '|';
+ cp = stpcpy (cp, "FNM_LEADING_DIR");
+ first = 0;
+ }
+#endif
+#ifdef FNM_CASEFOLD
+ if (flags & FNM_CASEFOLD)
+ {
+ if (! first)
+ *cp++ = '|';
+ cp = stpcpy (cp, "FNM_CASEFOLD");
+ first = 0;
+ }
+#endif
+#ifdef FNM_EXTMATCH
+ if (flags & FNM_EXTMATCH)
+ {
+ if (! first)
+ *cp++ = '|';
+ cp = stpcpy (cp, "FNM_EXTMATCH");
+ first = 0;
+ }
+#endif
+ if (cp == buf)
+ *cp++ = '0';
+ *cp = '\0';
+
+ return buf;
+}
+
+
+static char *
+escape (const char *str, size_t *reslenp, char **resbufp)
+{
+ size_t reslen = *reslenp;
+ char *resbuf = *resbufp;
+ size_t len = strlen (str);
+ char *wp;
+
+ if (2 * len + 1 > reslen)
+ {
+ resbuf = (char *) realloc (resbuf, 2 * len + 1);
+ if (resbuf == NULL)
+ error (EXIT_FAILURE, errno, "while allocating buffer for printing");
+ *reslenp = 2 * len + 1;
+ *resbufp = resbuf;
+ }
+
+ wp = resbuf;
+ while (*str != '\0')
+ if (*str == '\t')
+ {
+ *wp++ = '\\';
+ *wp++ = 't';
+ ++str;
+ }
+ else if (*str == '\n')
+ {
+ *wp++ = '\\';
+ *wp++ = 'n';
+ ++str;
+ }
+ else if (*str == '"')
+ {
+ *wp++ = '\\';
+ *wp++ = '"';
+ ++str;
+ }
+ else if (*str == '\\')
+ {
+ *wp++ = '\\';
+ *wp++ = '\\';
+ ++str;
+ }
+ else
+ *wp++ = *str++;
+
+ *wp = '\0';
+
+ return resbuf;
+}
diff --git a/test/misc/tst-fnmatch.input b/test/misc/tst-fnmatch.input
new file mode 100644
index 0000000..bf69c12
--- /dev/null
+++ b/test/misc/tst-fnmatch.input
@@ -0,0 +1,754 @@
+# Tests for fnmatch.
+# Copyright (C) 2000, 2001, 2004 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+# Contributes by Ulrich Drepper <drepper@redhat.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; see the file COPYING.LIB. If
+# not, see <http://www.gnu.org/licenses/>.
+
+
+# Derived from the IEEE 2003.2 text. The standard only contains some
+# wording describing the situations to be tested. It does not specify
+# any specific tests. I.e., the tests below are in no case sufficient.
+# They are hopefully necessary, though.
+
+# B.6 004(C)
+C "!#%+,-./01234567889" "!#%+,-./01234567889" 0
+C ":;=@ABCDEFGHIJKLMNO" ":;=@ABCDEFGHIJKLMNO" 0
+C "PQRSTUVWXYZ]abcdefg" "PQRSTUVWXYZ]abcdefg" 0
+C "hijklmnopqrstuvwxyz" "hijklmnopqrstuvwxyz" 0
+C "^_{}~" "^_{}~" 0
+
+# B.6 005(C)
+C "\"$&'()" "\\\"\\$\\&\\'\\(\\)" 0
+C "*?[\\`|" "\\*\\?\\[\\\\\\`\\|" 0
+C "<>" "\\<\\>" 0
+
+# B.6 006(C)
+C "?*[" "[?*[][?*[][?*[]" 0
+C "a/b" "?/b" 0
+
+# B.6 007(C)
+C "a/b" "a?b" 0
+C "a/b" "a/?" 0
+C "aa/b" "?/b" NOMATCH
+C "aa/b" "a?b" NOMATCH
+C "a/bb" "a/?" NOMATCH
+
+# B.6 009(C)
+C "abc" "[abc]" NOMATCH
+C "x" "[abc]" NOMATCH
+C "a" "[abc]" 0
+C "[" "[[abc]" 0
+C "a" "[][abc]" 0
+C "a]" "[]a]]" 0
+
+# B.6 010(C)
+C "xyz" "[!abc]" NOMATCH
+C "x" "[!abc]" 0
+C "a" "[!abc]" NOMATCH
+
+# B.6 011(C)
+C "]" "[][abc]" 0
+C "abc]" "[][abc]" NOMATCH
+C "[]abc" "[][]abc" NOMATCH
+C "]" "[!]]" NOMATCH
+C "aa]" "[!]a]" NOMATCH
+C "]" "[!a]" 0
+C "]]" "[!a]]" 0
+
+# B.6 012(C)
+C "a" "[[.a.]]" 0
+C "-" "[[.-.]]" 0
+C "-" "[[.-.][.].]]" 0
+C "-" "[[.].][.-.]]" 0
+C "-" "[[.-.][=u=]]" 0
+C "-" "[[.-.][:alpha:]]" 0
+C "a" "[![.a.]]" NOMATCH
+
+# B.6 013(C)
+C "a" "[[.b.]]" NOMATCH
+C "a" "[[.b.][.c.]]" NOMATCH
+C "a" "[[.b.][=b=]]" NOMATCH
+
+
+# B.6 015(C)
+C "a" "[[=a=]]" 0
+C "b" "[[=a=]b]" 0
+C "b" "[[=a=][=b=]]" 0
+C "a" "[[=a=][=b=]]" 0
+C "a" "[[=a=][.b.]]" 0
+C "a" "[[=a=][:digit:]]" 0
+
+# B.6 016(C)
+C "=" "[[=a=]b]" NOMATCH
+C "]" "[[=a=]b]" NOMATCH
+C "a" "[[=b=][=c=]]" NOMATCH
+C "a" "[[=b=][.].]]" NOMATCH
+C "a" "[[=b=][:digit:]]" NOMATCH
+
+# B.6 017(C)
+C "a" "[[:alnum:]]" 0
+C "a" "[![:alnum:]]" NOMATCH
+C "-" "[[:alnum:]]" NOMATCH
+C "a]a" "[[:alnum:]]a" NOMATCH
+C "-" "[[:alnum:]-]" 0
+C "aa" "[[:alnum:]]a" 0
+C "-" "[![:alnum:]]" 0
+C "]" "[!][:alnum:]]" NOMATCH
+C "[" "[![:alnum:][]" NOMATCH
+C "a" "[[:alnum:]]" 0
+C "b" "[[:alnum:]]" 0
+C "c" "[[:alnum:]]" 0
+C "d" "[[:alnum:]]" 0
+C "e" "[[:alnum:]]" 0
+C "f" "[[:alnum:]]" 0
+C "g" "[[:alnum:]]" 0
+C "h" "[[:alnum:]]" 0
+C "i" "[[:alnum:]]" 0
+C "j" "[[:alnum:]]" 0
+C "k" "[[:alnum:]]" 0
+C "l" "[[:alnum:]]" 0
+C "m" "[[:alnum:]]" 0
+C "n" "[[:alnum:]]" 0
+C "o" "[[:alnum:]]" 0
+C "p" "[[:alnum:]]" 0
+C "q" "[[:alnum:]]" 0
+C "r" "[[:alnum:]]" 0
+C "s" "[[:alnum:]]" 0
+C "t" "[[:alnum:]]" 0
+C "u" "[[:alnum:]]" 0
+C "v" "[[:alnum:]]" 0
+C "w" "[[:alnum:]]" 0
+C "x" "[[:alnum:]]" 0
+C "y" "[[:alnum:]]" 0
+C "z" "[[:alnum:]]" 0
+C "A" "[[:alnum:]]" 0
+C "B" "[[:alnum:]]" 0
+C "C" "[[:alnum:]]" 0
+C "D" "[[:alnum:]]" 0
+C "E" "[[:alnum:]]" 0
+C "F" "[[:alnum:]]" 0
+C "G" "[[:alnum:]]" 0
+C "H" "[[:alnum:]]" 0
+C "I" "[[:alnum:]]" 0
+C "J" "[[:alnum:]]" 0
+C "K" "[[:alnum:]]" 0
+C "L" "[[:alnum:]]" 0
+C "M" "[[:alnum:]]" 0
+C "N" "[[:alnum:]]" 0
+C "O" "[[:alnum:]]" 0
+C "P" "[[:alnum:]]" 0
+C "Q" "[[:alnum:]]" 0
+C "R" "[[:alnum:]]" 0
+C "S" "[[:alnum:]]" 0
+C "T" "[[:alnum:]]" 0
+C "U" "[[:alnum:]]" 0
+C "V" "[[:alnum:]]" 0
+C "W" "[[:alnum:]]" 0
+C "X" "[[:alnum:]]" 0
+C "Y" "[[:alnum:]]" 0
+C "Z" "[[:alnum:]]" 0
+C "0" "[[:alnum:]]" 0
+C "1" "[[:alnum:]]" 0
+C "2" "[[:alnum:]]" 0
+C "3" "[[:alnum:]]" 0
+C "4" "[[:alnum:]]" 0
+C "5" "[[:alnum:]]" 0
+C "6" "[[:alnum:]]" 0
+C "7" "[[:alnum:]]" 0
+C "8" "[[:alnum:]]" 0
+C "9" "[[:alnum:]]" 0
+C "!" "[[:alnum:]]" NOMATCH
+C "#" "[[:alnum:]]" NOMATCH
+C "%" "[[:alnum:]]" NOMATCH
+C "+" "[[:alnum:]]" NOMATCH
+C "," "[[:alnum:]]" NOMATCH
+C "-" "[[:alnum:]]" NOMATCH
+C "." "[[:alnum:]]" NOMATCH
+C "/" "[[:alnum:]]" NOMATCH
+C ":" "[[:alnum:]]" NOMATCH
+C ";" "[[:alnum:]]" NOMATCH
+C "=" "[[:alnum:]]" NOMATCH
+C "@" "[[:alnum:]]" NOMATCH
+C "[" "[[:alnum:]]" NOMATCH
+C "\\" "[[:alnum:]]" NOMATCH
+C "]" "[[:alnum:]]" NOMATCH
+C "^" "[[:alnum:]]" NOMATCH
+C "_" "[[:alnum:]]" NOMATCH
+C "{" "[[:alnum:]]" NOMATCH
+C "}" "[[:alnum:]]" NOMATCH
+C "~" "[[:alnum:]]" NOMATCH
+C "\"" "[[:alnum:]]" NOMATCH
+C "$" "[[:alnum:]]" NOMATCH
+C "&" "[[:alnum:]]" NOMATCH
+C "'" "[[:alnum:]]" NOMATCH
+C "(" "[[:alnum:]]" NOMATCH
+C ")" "[[:alnum:]]" NOMATCH
+C "*" "[[:alnum:]]" NOMATCH
+C "?" "[[:alnum:]]" NOMATCH
+C "`" "[[:alnum:]]" NOMATCH
+C "|" "[[:alnum:]]" NOMATCH
+C "<" "[[:alnum:]]" NOMATCH
+C ">" "[[:alnum:]]" NOMATCH
+C "\t" "[[:cntrl:]]" 0
+C "t" "[[:cntrl:]]" NOMATCH
+C "t" "[[:lower:]]" 0
+C "\t" "[[:lower:]]" NOMATCH
+C "T" "[[:lower:]]" NOMATCH
+C "\t" "[[:space:]]" 0
+C "t" "[[:space:]]" NOMATCH
+C "t" "[[:alpha:]]" 0
+C "\t" "[[:alpha:]]" NOMATCH
+C "0" "[[:digit:]]" 0
+C "\t" "[[:digit:]]" NOMATCH
+C "t" "[[:digit:]]" NOMATCH
+C "\t" "[[:print:]]" NOMATCH
+C "t" "[[:print:]]" 0
+C "T" "[[:upper:]]" 0
+C "\t" "[[:upper:]]" NOMATCH
+C "t" "[[:upper:]]" NOMATCH
+C "\t" "[[:blank:]]" 0
+C "t" "[[:blank:]]" NOMATCH
+C "\t" "[[:graph:]]" NOMATCH
+C "t" "[[:graph:]]" 0
+C "." "[[:punct:]]" 0
+C "t" "[[:punct:]]" NOMATCH
+C "\t" "[[:punct:]]" NOMATCH
+C "0" "[[:xdigit:]]" 0
+C "\t" "[[:xdigit:]]" NOMATCH
+C "a" "[[:xdigit:]]" 0
+C "A" "[[:xdigit:]]" 0
+C "t" "[[:xdigit:]]" NOMATCH
+C "a" "[[alpha]]" NOMATCH
+C "a" "[[alpha:]]" NOMATCH
+C "a]" "[[alpha]]" 0
+C "a]" "[[alpha:]]" 0
+C "a" "[[:alpha:][.b.]]" 0
+C "a" "[[:alpha:][=b=]]" 0
+C "a" "[[:alpha:][:digit:]]" 0
+C "a" "[[:digit:][:alpha:]]" 0
+
+# B.6 018(C)
+C "a" "[a-c]" 0
+C "b" "[a-c]" 0
+C "c" "[a-c]" 0
+C "a" "[b-c]" NOMATCH
+C "d" "[b-c]" NOMATCH
+C "B" "[a-c]" NOMATCH
+C "b" "[A-C]" NOMATCH
+C "" "[a-c]" NOMATCH
+C "as" "[a-ca-z]" NOMATCH
+C "a" "[[.a.]-c]" 0
+C "a" "[a-[.c.]]" 0
+C "a" "[[.a.]-[.c.]]" 0
+C "b" "[[.a.]-c]" 0
+C "b" "[a-[.c.]]" 0
+C "b" "[[.a.]-[.c.]]" 0
+C "c" "[[.a.]-c]" 0
+C "c" "[a-[.c.]]" 0
+C "c" "[[.a.]-[.c.]]" 0
+C "d" "[[.a.]-c]" NOMATCH
+C "d" "[a-[.c.]]" NOMATCH
+C "d" "[[.a.]-[.c.]]" NOMATCH
+
+# B.6 019(C)
+C "a" "[c-a]" NOMATCH
+C "a" "[[.c.]-a]" NOMATCH
+C "a" "[c-[.a.]]" NOMATCH
+C "a" "[[.c.]-[.a.]]" NOMATCH
+C "c" "[c-a]" NOMATCH
+C "c" "[[.c.]-a]" NOMATCH
+C "c" "[c-[.a.]]" NOMATCH
+C "c" "[[.c.]-[.a.]]" NOMATCH
+
+# B.6 020(C)
+C "a" "[a-c0-9]" 0
+C "d" "[a-c0-9]" NOMATCH
+C "B" "[a-c0-9]" NOMATCH
+
+# B.6 021(C)
+C "-" "[-a]" 0
+C "a" "[-b]" NOMATCH
+C "-" "[!-a]" NOMATCH
+C "a" "[!-b]" 0
+C "-" "[a-c-0-9]" 0
+C "b" "[a-c-0-9]" 0
+C "a:" "a[0-9-a]" NOMATCH
+C "a:" "a[09-a]" 0
+
+# B.6 024(C)
+C "" "*" 0
+C "asd/sdf" "*" 0
+
+# B.6 025(C)
+C "as" "[a-c][a-z]" 0
+C "as" "??" 0
+
+# B.6 026(C)
+C "asd/sdf" "as*df" 0
+C "asd/sdf" "as*" 0
+C "asd/sdf" "*df" 0
+C "asd/sdf" "as*dg" NOMATCH
+C "asdf" "as*df" 0
+C "asdf" "as*df?" NOMATCH
+C "asdf" "as*??" 0
+C "asdf" "a*???" 0
+C "asdf" "*????" 0
+C "asdf" "????*" 0
+C "asdf" "??*?" 0
+
+# B.6 027(C)
+C "/" "/" 0
+C "/" "/*" 0
+C "/" "*/" 0
+C "/" "/?" NOMATCH
+C "/" "?/" NOMATCH
+C "/" "?" 0
+C "." "?" 0
+C "/." "??" 0
+C "/" "[!a-c]" 0
+C "." "[!a-c]" 0
+
+# B.6 029(C)
+C "/" "/" 0 PATHNAME
+C "//" "//" 0 PATHNAME
+C "/.a" "/*" 0 PATHNAME
+C "/.a" "/?a" 0 PATHNAME
+C "/.a" "/[!a-z]a" 0 PATHNAME
+C "/.a/.b" "/*/?b" 0 PATHNAME
+
+# B.6 030(C)
+C "/" "?" NOMATCH PATHNAME
+C "/" "*" NOMATCH PATHNAME
+C "a/b" "a?b" NOMATCH PATHNAME
+C "/.a/.b" "/*b" NOMATCH PATHNAME
+
+# B.6 031(C)
+C "/$" "\\/\\$" 0
+C "/[" "\\/\\[" 0
+C "/[" "\\/[" NOMATCH
+
+# B.6 032(C)
+C "/$" "\\/\\$" NOMATCH NOESCAPE
+C "/\\$" "\\/\\$" NOMATCH NOESCAPE
+C "\\/\\$" "\\/\\$" 0 NOESCAPE
+
+# B.6 033(C)
+C ".asd" ".*" 0 PERIOD
+C "/.asd" "*" 0 PERIOD
+C "/as/.df" "*/?*f" 0 PERIOD
+C "..asd" ".[!a-z]*" 0 PERIOD
+
+# B.6 034(C)
+C ".asd" "*" NOMATCH PERIOD
+C ".asd" "?asd" NOMATCH PERIOD
+C ".asd" "[!a-z]*" NOMATCH PERIOD
+
+# B.6 035(C)
+C "/." "/." 0 PATHNAME|PERIOD
+C "/.a./.b." "/.*/.*" 0 PATHNAME|PERIOD
+C "/.a./.b." "/.??/.??" 0 PATHNAME|PERIOD
+
+# B.6 036(C)
+C "/." "*" NOMATCH PATHNAME|PERIOD
+C "/." "/*" NOMATCH PATHNAME|PERIOD
+C "/." "/?" NOMATCH PATHNAME|PERIOD
+C "/." "/[!a-z]" NOMATCH PATHNAME|PERIOD
+C "/a./.b." "/*/*" NOMATCH PATHNAME|PERIOD
+C "/a./.b." "/??/???" NOMATCH PATHNAME|PERIOD
+
+# Some home-grown tests.
+C "foobar" "foo*[abc]z" NOMATCH
+C "foobaz" "foo*[abc][xyz]" 0
+C "foobaz" "foo?*[abc][xyz]" 0
+C "foobaz" "foo?*[abc][x/yz]" 0
+C "foobaz" "foo?*[abc]/[xyz]" NOMATCH PATHNAME
+C "a" "a/" NOMATCH PATHNAME
+C "a/" "a" NOMATCH PATHNAME
+C "//a" "/a" NOMATCH PATHNAME
+C "/a" "//a" NOMATCH PATHNAME
+C "az" "[a-]z" 0
+C "bz" "[ab-]z" 0
+C "cz" "[ab-]z" NOMATCH
+C "-z" "[ab-]z" 0
+C "az" "[-a]z" 0
+C "bz" "[-ab]z" 0
+C "cz" "[-ab]z" NOMATCH
+C "-z" "[-ab]z" 0
+C "\\" "[\\\\-a]" 0
+C "_" "[\\\\-a]" 0
+C "a" "[\\\\-a]" 0
+C "-" "[\\\\-a]" NOMATCH
+C "\\" "[\\]-a]" NOMATCH
+C "_" "[\\]-a]" 0
+C "a" "[\\]-a]" 0
+C "]" "[\\]-a]" 0
+C "-" "[\\]-a]" NOMATCH
+C "\\" "[!\\\\-a]" NOMATCH
+C "_" "[!\\\\-a]" NOMATCH
+C "a" "[!\\\\-a]" NOMATCH
+C "-" "[!\\\\-a]" 0
+C "!" "[\\!-]" 0
+C "-" "[\\!-]" 0
+C "\\" "[\\!-]" NOMATCH
+C "Z" "[Z-\\\\]" 0
+C "[" "[Z-\\\\]" 0
+C "\\" "[Z-\\\\]" 0
+C "-" "[Z-\\\\]" NOMATCH
+C "Z" "[Z-\\]]" 0
+C "[" "[Z-\\]]" 0
+C "\\" "[Z-\\]]" 0
+C "]" "[Z-\\]]" 0
+C "-" "[Z-\\]]" NOMATCH
+
+# Following are tests outside the scope of IEEE 2003.2 since they are using
+# locales other than the C locale. The main focus of the tests is on the
+# handling of ranges and the recognition of character (vs bytes).
+de_DE.ISO-8859-1 "a" "[a-z]" 0
+de_DE.ISO-8859-1 "z" "[a-z]" 0
+de_DE.ISO-8859-1 "ä" "[a-z]" 0
+de_DE.ISO-8859-1 "ö" "[a-z]" 0
+de_DE.ISO-8859-1 "ü" "[a-z]" 0
+de_DE.ISO-8859-1 "A" "[a-z]" NOMATCH
+de_DE.ISO-8859-1 "Z" "[a-z]" NOMATCH
+de_DE.ISO-8859-1 "Ä" "[a-z]" NOMATCH
+de_DE.ISO-8859-1 "Ö" "[a-z]" NOMATCH
+de_DE.ISO-8859-1 "Ü" "[a-z]" NOMATCH
+de_DE.ISO-8859-1 "a" "[A-Z]" NOMATCH
+de_DE.ISO-8859-1 "z" "[A-Z]" NOMATCH
+de_DE.ISO-8859-1 "ä" "[A-Z]" NOMATCH
+de_DE.ISO-8859-1 "ö" "[A-Z]" NOMATCH
+de_DE.ISO-8859-1 "ü" "[A-Z]" NOMATCH
+de_DE.ISO-8859-1 "A" "[A-Z]" 0
+de_DE.ISO-8859-1 "Z" "[A-Z]" 0
+de_DE.ISO-8859-1 "Ä" "[A-Z]" 0
+de_DE.ISO-8859-1 "Ö" "[A-Z]" 0
+de_DE.ISO-8859-1 "Ü" "[A-Z]" 0
+de_DE.ISO-8859-1 "a" "[[:lower:]]" 0
+de_DE.ISO-8859-1 "z" "[[:lower:]]" 0
+de_DE.ISO-8859-1 "ä" "[[:lower:]]" 0
+de_DE.ISO-8859-1 "ö" "[[:lower:]]" 0
+de_DE.ISO-8859-1 "ü" "[[:lower:]]" 0
+de_DE.ISO-8859-1 "A" "[[:lower:]]" NOMATCH
+de_DE.ISO-8859-1 "Z" "[[:lower:]]" NOMATCH
+de_DE.ISO-8859-1 "Ä" "[[:lower:]]" NOMATCH
+de_DE.ISO-8859-1 "Ö" "[[:lower:]]" NOMATCH
+de_DE.ISO-8859-1 "Ü" "[[:lower:]]" NOMATCH
+de_DE.ISO-8859-1 "a" "[[:upper:]]" NOMATCH
+de_DE.ISO-8859-1 "z" "[[:upper:]]" NOMATCH
+de_DE.ISO-8859-1 "ä" "[[:upper:]]" NOMATCH
+de_DE.ISO-8859-1 "ö" "[[:upper:]]" NOMATCH
+de_DE.ISO-8859-1 "ü" "[[:upper:]]" NOMATCH
+de_DE.ISO-8859-1 "A" "[[:upper:]]" 0
+de_DE.ISO-8859-1 "Z" "[[:upper:]]" 0
+de_DE.ISO-8859-1 "Ä" "[[:upper:]]" 0
+de_DE.ISO-8859-1 "Ö" "[[:upper:]]" 0
+de_DE.ISO-8859-1 "Ü" "[[:upper:]]" 0
+de_DE.ISO-8859-1 "a" "[[:alpha:]]" 0
+de_DE.ISO-8859-1 "z" "[[:alpha:]]" 0
+de_DE.ISO-8859-1 "ä" "[[:alpha:]]" 0
+de_DE.ISO-8859-1 "ö" "[[:alpha:]]" 0
+de_DE.ISO-8859-1 "ü" "[[:alpha:]]" 0
+de_DE.ISO-8859-1 "A" "[[:alpha:]]" 0
+de_DE.ISO-8859-1 "Z" "[[:alpha:]]" 0
+de_DE.ISO-8859-1 "Ä" "[[:alpha:]]" 0
+de_DE.ISO-8859-1 "Ö" "[[:alpha:]]" 0
+de_DE.ISO-8859-1 "Ü" "[[:alpha:]]" 0
+
+de_DE.ISO-8859-1 "a" "[[=a=]b]" 0
+de_DE.ISO-8859-1 "â" "[[=a=]b]" 0
+de_DE.ISO-8859-1 "à" "[[=a=]b]" 0
+de_DE.ISO-8859-1 "á" "[[=a=]b]" 0
+de_DE.ISO-8859-1 "ä" "[[=a=]b]" 0
+de_DE.ISO-8859-1 "b" "[[=a=]b]" 0
+de_DE.ISO-8859-1 "c" "[[=a=]b]" NOMATCH
+de_DE.ISO-8859-1 "a" "[[=â=]b]" 0
+de_DE.ISO-8859-1 "â" "[[=â=]b]" 0
+de_DE.ISO-8859-1 "à" "[[=â=]b]" 0
+de_DE.ISO-8859-1 "á" "[[=â=]b]" 0
+de_DE.ISO-8859-1 "ä" "[[=â=]b]" 0
+de_DE.ISO-8859-1 "b" "[[=â=]b]" 0
+de_DE.ISO-8859-1 "c" "[[=â=]b]" NOMATCH
+de_DE.ISO-8859-1 "a" "[[=à=]b]" 0
+de_DE.ISO-8859-1 "â" "[[=à=]b]" 0
+de_DE.ISO-8859-1 "à" "[[=à=]b]" 0
+de_DE.ISO-8859-1 "á" "[[=à=]b]" 0
+de_DE.ISO-8859-1 "ä" "[[=à=]b]" 0
+de_DE.ISO-8859-1 "b" "[[=à=]b]" 0
+de_DE.ISO-8859-1 "c" "[[=à=]b]" NOMATCH
+de_DE.ISO-8859-1 "a" "[[=á=]b]" 0
+de_DE.ISO-8859-1 "â" "[[=á=]b]" 0
+de_DE.ISO-8859-1 "à" "[[=á=]b]" 0
+de_DE.ISO-8859-1 "á" "[[=á=]b]" 0
+de_DE.ISO-8859-1 "ä" "[[=á=]b]" 0
+de_DE.ISO-8859-1 "b" "[[=á=]b]" 0
+de_DE.ISO-8859-1 "c" "[[=á=]b]" NOMATCH
+de_DE.ISO-8859-1 "a" "[[=ä=]b]" 0
+de_DE.ISO-8859-1 "â" "[[=ä=]b]" 0
+de_DE.ISO-8859-1 "à" "[[=ä=]b]" 0
+de_DE.ISO-8859-1 "á" "[[=ä=]b]" 0
+de_DE.ISO-8859-1 "ä" "[[=ä=]b]" 0
+de_DE.ISO-8859-1 "b" "[[=ä=]b]" 0
+de_DE.ISO-8859-1 "c" "[[=ä=]b]" NOMATCH
+
+de_DE.ISO-8859-1 "aa" "[[.a.]]a" 0
+de_DE.ISO-8859-1 "ba" "[[.a.]]a" NOMATCH
+
+
+# And with a multibyte character set.
+de_DE.UTF-8 "a" "[a-z]" 0
+de_DE.UTF-8 "z" "[a-z]" 0
+de_DE.UTF-8 "ä" "[a-z]" 0
+de_DE.UTF-8 "ö" "[a-z]" 0
+de_DE.UTF-8 "ü" "[a-z]" 0
+de_DE.UTF-8 "A" "[a-z]" NOMATCH
+de_DE.UTF-8 "Z" "[a-z]" NOMATCH
+de_DE.UTF-8 "Ä" "[a-z]" NOMATCH
+de_DE.UTF-8 "Ö" "[a-z]" NOMATCH
+de_DE.UTF-8 "Ü" "[a-z]" NOMATCH
+de_DE.UTF-8 "a" "[A-Z]" NOMATCH
+de_DE.UTF-8 "z" "[A-Z]" NOMATCH
+de_DE.UTF-8 "ä" "[A-Z]" NOMATCH
+de_DE.UTF-8 "ö" "[A-Z]" NOMATCH
+de_DE.UTF-8 "ü" "[A-Z]" NOMATCH
+de_DE.UTF-8 "A" "[A-Z]" 0
+de_DE.UTF-8 "Z" "[A-Z]" 0
+de_DE.UTF-8 "Ä" "[A-Z]" 0
+de_DE.UTF-8 "Ö" "[A-Z]" 0
+de_DE.UTF-8 "Ü" "[A-Z]" 0
+de_DE.UTF-8 "a" "[[:lower:]]" 0
+de_DE.UTF-8 "z" "[[:lower:]]" 0
+de_DE.UTF-8 "ä" "[[:lower:]]" 0
+de_DE.UTF-8 "ö" "[[:lower:]]" 0
+de_DE.UTF-8 "ü" "[[:lower:]]" 0
+de_DE.UTF-8 "A" "[[:lower:]]" NOMATCH
+de_DE.UTF-8 "Z" "[[:lower:]]" NOMATCH
+de_DE.UTF-8 "Ä" "[[:lower:]]" NOMATCH
+de_DE.UTF-8 "Ö" "[[:lower:]]" NOMATCH
+de_DE.UTF-8 "Ü" "[[:lower:]]" NOMATCH
+de_DE.UTF-8 "a" "[[:upper:]]" NOMATCH
+de_DE.UTF-8 "z" "[[:upper:]]" NOMATCH
+de_DE.UTF-8 "ä" "[[:upper:]]" NOMATCH
+de_DE.UTF-8 "ö" "[[:upper:]]" NOMATCH
+de_DE.UTF-8 "ü" "[[:upper:]]" NOMATCH
+de_DE.UTF-8 "A" "[[:upper:]]" 0
+de_DE.UTF-8 "Z" "[[:upper:]]" 0
+de_DE.UTF-8 "Ä" "[[:upper:]]" 0
+de_DE.UTF-8 "Ö" "[[:upper:]]" 0
+de_DE.UTF-8 "Ü" "[[:upper:]]" 0
+de_DE.UTF-8 "a" "[[:alpha:]]" 0
+de_DE.UTF-8 "z" "[[:alpha:]]" 0
+de_DE.UTF-8 "ä" "[[:alpha:]]" 0
+de_DE.UTF-8 "ö" "[[:alpha:]]" 0
+de_DE.UTF-8 "ü" "[[:alpha:]]" 0
+de_DE.UTF-8 "A" "[[:alpha:]]" 0
+de_DE.UTF-8 "Z" "[[:alpha:]]" 0
+de_DE.UTF-8 "Ä" "[[:alpha:]]" 0
+de_DE.UTF-8 "Ö" "[[:alpha:]]" 0
+de_DE.UTF-8 "Ü" "[[:alpha:]]" 0
+
+de_DE.UTF-8 "a" "[[=a=]b]" 0
+de_DE.UTF-8 "â" "[[=a=]b]" 0
+de_DE.UTF-8 "à" "[[=a=]b]" 0
+de_DE.UTF-8 "á" "[[=a=]b]" 0
+de_DE.UTF-8 "ä" "[[=a=]b]" 0
+de_DE.UTF-8 "b" "[[=a=]b]" 0
+de_DE.UTF-8 "c" "[[=a=]b]" NOMATCH
+de_DE.UTF-8 "a" "[[=â=]b]" 0
+de_DE.UTF-8 "â" "[[=â=]b]" 0
+de_DE.UTF-8 "à" "[[=â=]b]" 0
+de_DE.UTF-8 "á" "[[=â=]b]" 0
+de_DE.UTF-8 "ä" "[[=â=]b]" 0
+de_DE.UTF-8 "b" "[[=â=]b]" 0
+de_DE.UTF-8 "c" "[[=â=]b]" NOMATCH
+de_DE.UTF-8 "a" "[[=à=]b]" 0
+de_DE.UTF-8 "â" "[[=à=]b]" 0
+de_DE.UTF-8 "à" "[[=à=]b]" 0
+de_DE.UTF-8 "á" "[[=à=]b]" 0
+de_DE.UTF-8 "ä" "[[=à=]b]" 0
+de_DE.UTF-8 "b" "[[=à=]b]" 0
+de_DE.UTF-8 "c" "[[=à=]b]" NOMATCH
+de_DE.UTF-8 "a" "[[=á=]b]" 0
+de_DE.UTF-8 "â" "[[=á=]b]" 0
+de_DE.UTF-8 "à" "[[=á=]b]" 0
+de_DE.UTF-8 "á" "[[=á=]b]" 0
+de_DE.UTF-8 "ä" "[[=á=]b]" 0
+de_DE.UTF-8 "b" "[[=á=]b]" 0
+de_DE.UTF-8 "c" "[[=á=]b]" NOMATCH
+de_DE.UTF-8 "a" "[[=ä=]b]" 0
+de_DE.UTF-8 "â" "[[=ä=]b]" 0
+de_DE.UTF-8 "à" "[[=ä=]b]" 0
+de_DE.UTF-8 "á" "[[=ä=]b]" 0
+de_DE.UTF-8 "ä" "[[=ä=]b]" 0
+de_DE.UTF-8 "b" "[[=ä=]b]" 0
+de_DE.UTF-8 "c" "[[=ä=]b]" NOMATCH
+
+de_DE.UTF-8 "aa" "[[.a.]]a" 0
+de_DE.UTF-8 "ba" "[[.a.]]a" NOMATCH
+
+
+# Test of GNU extensions.
+C "x" "x" 0 PATHNAME|LEADING_DIR
+C "x/y" "x" 0 PATHNAME|LEADING_DIR
+C "x/y/z" "x" 0 PATHNAME|LEADING_DIR
+C "x" "*" 0 PATHNAME|LEADING_DIR
+C "x/y" "*" 0 PATHNAME|LEADING_DIR
+C "x/y/z" "*" 0 PATHNAME|LEADING_DIR
+C "x" "*x" 0 PATHNAME|LEADING_DIR
+C "x/y" "*x" 0 PATHNAME|LEADING_DIR
+C "x/y/z" "*x" 0 PATHNAME|LEADING_DIR
+C "x" "x*" 0 PATHNAME|LEADING_DIR
+C "x/y" "x*" 0 PATHNAME|LEADING_DIR
+C "x/y/z" "x*" 0 PATHNAME|LEADING_DIR
+C "x" "a" NOMATCH PATHNAME|LEADING_DIR
+C "x/y" "a" NOMATCH PATHNAME|LEADING_DIR
+C "x/y/z" "a" NOMATCH PATHNAME|LEADING_DIR
+C "x" "x/y" NOMATCH PATHNAME|LEADING_DIR
+C "x/y" "x/y" 0 PATHNAME|LEADING_DIR
+C "x/y/z" "x/y" 0 PATHNAME|LEADING_DIR
+C "x" "x?y" NOMATCH PATHNAME|LEADING_DIR
+C "x/y" "x?y" NOMATCH PATHNAME|LEADING_DIR
+C "x/y/z" "x?y" NOMATCH PATHNAME|LEADING_DIR
+
+# ksh style matching.
+C "abcd" "?@(a|b)*@(c)d" 0 EXTMATCH
+C "/dev/udp/129.22.8.102/45" "/dev/@(tcp|udp)/*/*" 0 PATHNAME|EXTMATCH
+C "12" "[1-9]*([0-9])" 0 EXTMATCH
+C "12abc" "[1-9]*([0-9])" NOMATCH EXTMATCH
+C "1" "[1-9]*([0-9])" 0 EXTMATCH
+C "07" "+([0-7])" 0 EXTMATCH
+C "0377" "+([0-7])" 0 EXTMATCH
+C "09" "+([0-7])" NOMATCH EXTMATCH
+C "paragraph" "para@(chute|graph)" 0 EXTMATCH
+C "paramour" "para@(chute|graph)" NOMATCH EXTMATCH
+C "para991" "para?([345]|99)1" 0 EXTMATCH
+C "para381" "para?([345]|99)1" NOMATCH EXTMATCH
+C "paragraph" "para*([0-9])" NOMATCH EXTMATCH
+C "para" "para*([0-9])" 0 EXTMATCH
+C "para13829383746592" "para*([0-9])" 0 EXTMATCH
+C "paragraph" "para+([0-9])" NOMATCH EXTMATCH
+C "para" "para+([0-9])" NOMATCH EXTMATCH
+C "para987346523" "para+([0-9])" 0 EXTMATCH
+C "paragraph" "para!(*.[0-9])" 0 EXTMATCH
+C "para.38" "para!(*.[0-9])" 0 EXTMATCH
+C "para.graph" "para!(*.[0-9])" 0 EXTMATCH
+C "para39" "para!(*.[0-9])" 0 EXTMATCH
+C "" "*(0|1|3|5|7|9)" 0 EXTMATCH
+C "137577991" "*(0|1|3|5|7|9)" 0 EXTMATCH
+C "2468" "*(0|1|3|5|7|9)" NOMATCH EXTMATCH
+C "1358" "*(0|1|3|5|7|9)" NOMATCH EXTMATCH
+C "file.c" "*.c?(c)" 0 EXTMATCH
+C "file.C" "*.c?(c)" NOMATCH EXTMATCH
+C "file.cc" "*.c?(c)" 0 EXTMATCH
+C "file.ccc" "*.c?(c)" NOMATCH EXTMATCH
+C "parse.y" "!(*.c|*.h|Makefile.in|config*|README)" 0 EXTMATCH
+C "shell.c" "!(*.c|*.h|Makefile.in|config*|README)" NOMATCH EXTMATCH
+C "Makefile" "!(*.c|*.h|Makefile.in|config*|README)" 0 EXTMATCH
+C "VMS.FILE;1" "*\;[1-9]*([0-9])" 0 EXTMATCH
+C "VMS.FILE;0" "*\;[1-9]*([0-9])" NOMATCH EXTMATCH
+C "VMS.FILE;" "*\;[1-9]*([0-9])" NOMATCH EXTMATCH
+C "VMS.FILE;139" "*\;[1-9]*([0-9])" 0 EXTMATCH
+C "VMS.FILE;1N" "*\;[1-9]*([0-9])" NOMATCH EXTMATCH
+C "abcfefg" "ab**(e|f)" 0 EXTMATCH
+C "abcfefg" "ab**(e|f)g" 0 EXTMATCH
+C "ab" "ab*+(e|f)" NOMATCH EXTMATCH
+C "abef" "ab***ef" 0 EXTMATCH
+C "abef" "ab**" 0 EXTMATCH
+C "fofo" "*(f*(o))" 0 EXTMATCH
+C "ffo" "*(f*(o))" 0 EXTMATCH
+C "foooofo" "*(f*(o))" 0 EXTMATCH
+C "foooofof" "*(f*(o))" 0 EXTMATCH
+C "fooofoofofooo" "*(f*(o))" 0 EXTMATCH
+C "foooofof" "*(f+(o))" NOMATCH EXTMATCH
+C "xfoooofof" "*(f*(o))" NOMATCH EXTMATCH
+C "foooofofx" "*(f*(o))" NOMATCH EXTMATCH
+C "ofxoofxo" "*(*(of*(o)x)o)" 0 EXTMATCH
+C "ofooofoofofooo" "*(f*(o))" NOMATCH EXTMATCH
+C "foooxfooxfoxfooox" "*(f*(o)x)" 0 EXTMATCH
+C "foooxfooxofoxfooox" "*(f*(o)x)" NOMATCH EXTMATCH
+C "foooxfooxfxfooox" "*(f*(o)x)" 0 EXTMATCH
+C "ofxoofxo" "*(*(of*(o)x)o)" 0 EXTMATCH
+C "ofoooxoofxo" "*(*(of*(o)x)o)" 0 EXTMATCH
+C "ofoooxoofxoofoooxoofxo" "*(*(of*(o)x)o)" 0 EXTMATCH
+C "ofoooxoofxoofoooxoofxoo" "*(*(of*(o)x)o)" 0 EXTMATCH
+C "ofoooxoofxoofoooxoofxofo" "*(*(of*(o)x)o)" NOMATCH EXTMATCH
+C "ofoooxoofxoofoooxoofxooofxofxo" "*(*(of*(o)x)o)" 0 EXTMATCH
+C "aac" "*(@(a))a@(c)" 0 EXTMATCH
+C "ac" "*(@(a))a@(c)" 0 EXTMATCH
+C "c" "*(@(a))a@(c)" NOMATCH EXTMATCH
+C "aaac" "*(@(a))a@(c)" 0 EXTMATCH
+C "baaac" "*(@(a))a@(c)" NOMATCH EXTMATCH
+C "abcd" "?@(a|b)*@(c)d" 0 EXTMATCH
+C "abcd" "@(ab|a*@(b))*(c)d" 0 EXTMATCH
+C "acd" "@(ab|a*(b))*(c)d" 0 EXTMATCH
+C "abbcd" "@(ab|a*(b))*(c)d" 0 EXTMATCH
+C "effgz" "@(b+(c)d|e*(f)g?|?(h)i@(j|k))" 0 EXTMATCH
+C "efgz" "@(b+(c)d|e*(f)g?|?(h)i@(j|k))" 0 EXTMATCH
+C "egz" "@(b+(c)d|e*(f)g?|?(h)i@(j|k))" 0 EXTMATCH
+C "egzefffgzbcdij" "*(b+(c)d|e*(f)g?|?(h)i@(j|k))" 0 EXTMATCH
+C "egz" "@(b+(c)d|e+(f)g?|?(h)i@(j|k))" NOMATCH EXTMATCH
+C "ofoofo" "*(of+(o))" 0 EXTMATCH
+C "oxfoxoxfox" "*(oxf+(ox))" 0 EXTMATCH
+C "oxfoxfox" "*(oxf+(ox))" NOMATCH EXTMATCH
+C "ofoofo" "*(of+(o)|f)" 0 EXTMATCH
+C "foofoofo" "@(foo|f|fo)*(f|of+(o))" 0 EXTMATCH
+C "oofooofo" "*(of|oof+(o))" 0 EXTMATCH
+C "fffooofoooooffoofffooofff" "*(*(f)*(o))" 0 EXTMATCH
+C "fofoofoofofoo" "*(fo|foo)" 0 EXTMATCH
+C "foo" "!(x)" 0 EXTMATCH
+C "foo" "!(x)*" 0 EXTMATCH
+C "foo" "!(foo)" NOMATCH EXTMATCH
+C "foo" "!(foo)*" 0 EXTMATCH
+C "foobar" "!(foo)" 0 EXTMATCH
+C "foobar" "!(foo)*" 0 EXTMATCH
+C "moo.cow" "!(*.*).!(*.*)" 0 EXTMATCH
+C "mad.moo.cow" "!(*.*).!(*.*)" NOMATCH EXTMATCH
+C "mucca.pazza" "mu!(*(c))?.pa!(*(z))?" NOMATCH EXTMATCH
+C "fff" "!(f)" 0 EXTMATCH
+C "fff" "*(!(f))" 0 EXTMATCH
+C "fff" "+(!(f))" 0 EXTMATCH
+C "ooo" "!(f)" 0 EXTMATCH
+C "ooo" "*(!(f))" 0 EXTMATCH
+C "ooo" "+(!(f))" 0 EXTMATCH
+C "foo" "!(f)" 0 EXTMATCH
+C "foo" "*(!(f))" 0 EXTMATCH
+C "foo" "+(!(f))" 0 EXTMATCH
+C "f" "!(f)" NOMATCH EXTMATCH
+C "f" "*(!(f))" NOMATCH EXTMATCH
+C "f" "+(!(f))" NOMATCH EXTMATCH
+C "foot" "@(!(z*)|*x)" 0 EXTMATCH
+C "zoot" "@(!(z*)|*x)" NOMATCH EXTMATCH
+C "foox" "@(!(z*)|*x)" 0 EXTMATCH
+C "zoox" "@(!(z*)|*x)" 0 EXTMATCH
+C "foo" "*(!(foo)) 0 EXTMATCH
+C "foob" "!(foo)b*" NOMATCH EXTMATCH
+C "foobb" "!(foo)b*" 0 EXTMATCH
+C "[" "*([a[])" 0 EXTMATCH
+C "]" "*([]a[])" 0 EXTMATCH
+C "a" "*([]a[])" 0 EXTMATCH
+C "b" "*([!]a[])" 0 EXTMATCH
+C "[" "*([!]a[]|[[])" 0 EXTMATCH
+C "]" "*([!]a[]|[]])" 0 EXTMATCH
+C "[" "!([!]a[])" 0 EXTMATCH
+C "]" "!([!]a[])" 0 EXTMATCH
+C ")" "*([)])" 0 EXTMATCH
+C "*" "*([*(])" 0 EXTMATCH
+C "abcd" "*!(|a)cd" 0 EXTMATCH
+C "ab/.a" "+([abc])/*" NOMATCH EXTMATCH|PATHNAME|PERIOD
+C "" "" 0
+C "" "" 0 EXTMATCH
+C "" "*([abc])" 0 EXTMATCH
+C "" "?([abc])" 0 EXTMATCH
diff --git a/test/misc/tst-gnuglob.c b/test/misc/tst-gnuglob.c
new file mode 100644
index 0000000..53bc0cf
--- /dev/null
+++ b/test/misc/tst-gnuglob.c
@@ -0,0 +1,446 @@
+/* Test the GNU extensions in glob which allow the user to provide callbacks
+ for the filesystem access functions.
+ Copyright (C) 2001-2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@redhat.com>, 2001.
+
+ 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 <dirent.h>
+#include <errno.h>
+#include <error.h>
+#include <glob.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+
+// #define DEBUG
+#ifdef DEBUG
+# define PRINTF(fmt, args...) printf (fmt, ##args)
+#else
+# define PRINTF(fmt, args...)
+#endif
+
+
+#ifdef GLOB_ALTDIRFUNC
+static struct
+{
+ const char *name;
+ int level;
+ int type;
+} filesystem[] =
+{
+ { ".", 1, DT_DIR },
+ { "..", 1, DT_DIR },
+ { "file1lev1", 1, DT_REG },
+ { "file2lev1", 1, DT_UNKNOWN },
+ { "dir1lev1", 1, DT_UNKNOWN },
+ { ".", 2, DT_DIR },
+ { "..", 2, DT_DIR },
+ { "file1lev2", 2, DT_REG },
+ { "dir1lev2", 2, DT_DIR },
+ { ".", 3, DT_DIR },
+ { "..", 3, DT_DIR },
+ { "dir2lev2", 2, DT_DIR },
+ { ".", 3, DT_DIR },
+ { "..", 3, DT_DIR },
+ { ".foo", 3, DT_REG },
+ { "dir1lev3", 3, DT_DIR },
+ { ".", 4, DT_DIR },
+ { "..", 4, DT_DIR },
+ { "file1lev4", 4, DT_REG },
+ { "file1lev3", 3, DT_REG },
+ { "file2lev3", 3, DT_REG },
+ { "file2lev2", 2, DT_REG },
+ { "file3lev2", 2, DT_REG },
+ { "dir3lev2", 2, DT_DIR },
+ { ".", 3, DT_DIR },
+ { "..", 3, DT_DIR },
+ { "file3lev3", 3, DT_REG },
+ { "file4lev3", 3, DT_REG },
+ { "dir2lev1", 1, DT_DIR },
+ { ".", 2, DT_DIR },
+ { "..", 2, DT_DIR },
+ { "dir1lev2", 2, DT_UNKNOWN },
+ { ".", 3, DT_DIR },
+ { "..", 3, DT_DIR },
+ { ".foo", 3, DT_REG },
+ { ".dir", 3, DT_DIR },
+ { ".", 4, DT_DIR },
+ { "..", 4, DT_DIR },
+ { "hidden", 4, DT_REG }
+};
+#define nfiles (sizeof (filesystem) / sizeof (filesystem[0]))
+
+
+typedef struct
+{
+ int level;
+ int idx;
+ struct dirent d;
+ char room_for_dirent[NAME_MAX];
+} my_DIR;
+
+
+static long int
+find_file (const char *s)
+{
+ int level = 1;
+ long int idx = 0;
+
+ if (strcmp (s, ".") == 0)
+ return 0;
+
+ if (s[0] == '.' && s[1] == '/')
+ s += 2;
+
+ while (*s != '\0')
+ {
+ char *endp = strchrnul (s, '/');
+
+ PRINTF ("looking for %.*s, level %d\n", (int) (endp - s), s, level);
+
+ while (idx < nfiles && filesystem[idx].level >= level)
+ {
+ if (filesystem[idx].level == level
+ && memcmp (s, filesystem[idx].name, endp - s) == 0
+ && filesystem[idx].name[endp - s] == '\0')
+ break;
+ ++idx;
+ }
+
+ if (idx == nfiles || filesystem[idx].level < level)
+ {
+ errno = ENOENT;
+ return -1;
+ }
+
+ if (*endp == '\0')
+ return idx + 1;
+
+ if (filesystem[idx].type != DT_DIR
+ && (idx + 1 >= nfiles
+ || filesystem[idx].level >= filesystem[idx + 1].level))
+ {
+ errno = ENOTDIR;
+ return -1;
+ }
+
+ ++idx;
+
+ s = endp + 1;
+ ++level;
+ }
+
+ errno = ENOENT;
+ return -1;
+}
+
+
+static void *
+my_opendir (const char *s)
+{
+ long int idx = find_file (s);
+ my_DIR *dir;
+
+
+ if (idx == -1)
+ {
+ PRINTF ("my_opendir(\"%s\") == NULL\n", s);
+ return NULL;
+ }
+
+ dir = (my_DIR *) malloc (sizeof (my_DIR));
+ if (dir == NULL)
+ error (EXIT_FAILURE, errno, "cannot allocate directory handle");
+
+ dir->level = filesystem[idx].level;
+ dir->idx = idx;
+
+ PRINTF ("my_opendir(\"%s\") == { level: %d, idx: %ld }\n",
+ s, filesystem[idx].level, idx);
+
+ return dir;
+}
+
+
+static struct dirent *
+my_readdir (void *gdir)
+{
+ my_DIR *dir = gdir;
+
+ if (dir->idx == -1)
+ {
+ PRINTF ("my_readdir ({ level: %d, idx: %ld }) = NULL\n",
+ dir->level, (long int) dir->idx);
+ return NULL;
+ }
+
+ while (dir->idx < nfiles && filesystem[dir->idx].level > dir->level)
+ ++dir->idx;
+
+ if (dir->idx == nfiles || filesystem[dir->idx].level < dir->level)
+ {
+ dir->idx = -1;
+ PRINTF ("my_readdir ({ level: %d, idx: %ld }) = NULL\n",
+ dir->level, (long int) dir->idx);
+ return NULL;
+ }
+
+ dir->d.d_ino = dir->idx;
+
+#ifdef _DIRENT_HAVE_D_TYPE
+ dir->d.d_type = filesystem[dir->idx].type;
+#endif
+
+ strcpy (dir->d.d_name, filesystem[dir->idx].name);
+
+#ifdef _DIRENT_HAVE_D_TYPE
+ PRINTF ("my_readdir ({ level: %d, idx: %ld }) = { d_ino: %ld, d_type: %d, d_name: \"%s\" }\n",
+ dir->level, (long int) dir->idx, dir->d.d_ino, dir->d.d_type,
+ dir->d.d_name);
+#else
+ PRINTF ("my_readdir ({ level: %d, idx: %ld }) = { d_ino: %ld, d_name: \"%s\" }\n",
+ dir->level, (long int) dir->idx, dir->d.d_ino,
+ dir->d.d_name);
+#endif
+
+ ++dir->idx;
+
+ return &dir->d;
+}
+
+
+static void
+my_closedir (void *dir)
+{
+ PRINTF ("my_closedir ()\n");
+ free (dir);
+}
+
+
+/* We use this function for lstat as well since we don't have any. */
+static int
+my_stat (const char *name, struct stat *st)
+{
+ long int idx = find_file (name);
+
+ if (idx == -1)
+ {
+ PRINTF ("my_stat (\"%s\", ...) = -1 (%s)\n", name, strerror (errno));
+ return -1;
+ }
+
+ memset (st, '\0', sizeof (*st));
+
+ if (filesystem[idx].type == DT_UNKNOWN)
+ st->st_mode = DTTOIF (idx + 1 < nfiles
+ && filesystem[idx].level < filesystem[idx + 1].level
+ ? DT_DIR : DT_REG) | 0777;
+ else
+ st->st_mode = DTTOIF (filesystem[idx].type) | 0777;
+
+ PRINTF ("my_stat (\"%s\", { st_mode: %o }) = 0\n", name, st->st_mode);
+
+ return 0;
+}
+
+
+static const char *glob_errstring[] =
+{
+ [GLOB_NOSPACE] = "out of memory",
+ [GLOB_ABORTED] = "read error",
+ [GLOB_NOMATCH] = "no matches found"
+};
+#define nglob_errstring (sizeof (glob_errstring) / sizeof (glob_errstring[0]))
+
+
+static const char *
+flagstr (int flags)
+{
+ const char *strs[] =
+ {
+ "GLOB_ERR", "GLOB_MARK", "GLOB_NOSORT", "GLOB_DOOFSS", "GLOB_NOCHECK",
+ "GLOB_APPEND", "GLOB_NOESCAPE", "GLOB_PERIOD", "GLOB_MAGCHAR",
+ "GLOB_ALTDIRFUNC", "GLOB_BRACE", "GLOB_NOMAGIC", "GLOB_TILDE",
+ "GLOB_ONLYDIR", "GLOB_TILDECHECK"
+ };
+#define nstrs (sizeof (strs) / sizeof (strs[0]))
+ static char buf[100];
+ char *cp = buf;
+ int cnt;
+
+ for (cnt = 0; cnt < nstrs; ++cnt)
+ if (flags & (1 << cnt))
+ {
+ flags &= ~(1 << cnt);
+ if (cp != buf)
+ *cp++ = '|';
+ cp = stpcpy (cp, strs[cnt]);
+ }
+
+ if (flags != 0)
+ {
+ if (cp != buf)
+ *cp++ = '|';
+ sprintf (cp, "%#x", flags);
+ }
+
+ return buf;
+}
+
+
+static int
+test_result (const char *fmt, int flags, glob_t *gl, const char *str[])
+{
+ size_t cnt;
+ int result = 0;
+
+ printf ("results for glob (\"%s\", %s)\n", fmt, flagstr (flags));
+ for (cnt = 0; cnt < gl->gl_pathc && str[cnt] != NULL; ++cnt)
+ {
+ int ok = strcmp (gl->gl_pathv[cnt], str[cnt]) == 0;
+ const char *errstr = "";
+
+ if (! ok)
+ {
+ size_t inner;
+
+ for (inner = 0; str[inner] != NULL; ++inner)
+ if (strcmp (gl->gl_pathv[cnt], str[inner]) == 0)
+ break;
+
+ if (str[inner] == NULL)
+ errstr = ok ? "" : " *** WRONG";
+ else
+ errstr = ok ? "" : " * wrong position";
+
+ result = 1;
+ }
+
+ printf (" %s%s\n", gl->gl_pathv[cnt], errstr);
+ }
+ puts ("");
+
+ if (str[cnt] != NULL || cnt < gl->gl_pathc)
+ {
+ puts (" *** incorrect number of entries");
+ result = 1;
+ }
+
+ return result;
+}
+
+
+int
+main (void)
+{
+ glob_t gl;
+ int errval;
+ int result = 0;
+ const char *fmt;
+ int flags;
+
+ memset (&gl, '\0', sizeof (gl));
+
+ gl.gl_closedir = my_closedir;
+ gl.gl_readdir = my_readdir;
+ gl.gl_opendir = my_opendir;
+ gl.gl_lstat = my_stat;
+ gl.gl_stat = my_stat;
+
+#define test(a, b, c...) \
+ fmt = a; \
+ flags = b; \
+ errval = glob (fmt, flags, NULL, &gl); \
+ if (errval != 0) \
+ { \
+ printf ("glob (\"%s\", %s) failed: %s\n", fmt, flagstr (flags), \
+ errval >= 0 && errval < nglob_errstring \
+ ? glob_errstring[errval] : "???"); \
+ result = 1; \
+ } \
+ else \
+ result |= test_result (fmt, flags, &gl, (const char *[]) { c, NULL })
+
+ test ("*/*/*", GLOB_ALTDIRFUNC,
+ "dir1lev1/dir2lev2/dir1lev3",
+ "dir1lev1/dir2lev2/file1lev3",
+ "dir1lev1/dir2lev2/file2lev3",
+ "dir1lev1/dir3lev2/file3lev3",
+ "dir1lev1/dir3lev2/file4lev3");
+
+ test ("*/*/*", GLOB_ALTDIRFUNC | GLOB_PERIOD,
+ "dir1lev1/dir1lev2/.",
+ "dir1lev1/dir1lev2/..",
+ "dir1lev1/dir2lev2/.",
+ "dir1lev1/dir2lev2/..",
+ "dir1lev1/dir2lev2/.foo",
+ "dir1lev1/dir2lev2/dir1lev3",
+ "dir1lev1/dir2lev2/file1lev3",
+ "dir1lev1/dir2lev2/file2lev3",
+ "dir1lev1/dir3lev2/.",
+ "dir1lev1/dir3lev2/..",
+ "dir1lev1/dir3lev2/file3lev3",
+ "dir1lev1/dir3lev2/file4lev3",
+ "dir2lev1/dir1lev2/.",
+ "dir2lev1/dir1lev2/..",
+ "dir2lev1/dir1lev2/.dir",
+ "dir2lev1/dir1lev2/.foo");
+
+ test ("*/*/.*", GLOB_ALTDIRFUNC,
+ "dir1lev1/dir1lev2/.",
+ "dir1lev1/dir1lev2/..",
+ "dir1lev1/dir2lev2/.",
+ "dir1lev1/dir2lev2/..",
+ "dir1lev1/dir2lev2/.foo",
+ "dir1lev1/dir3lev2/.",
+ "dir1lev1/dir3lev2/..",
+ "dir2lev1/dir1lev2/.",
+ "dir2lev1/dir1lev2/..",
+ "dir2lev1/dir1lev2/.dir",
+ "dir2lev1/dir1lev2/.foo");
+
+ test ("*1*/*2*/.*", GLOB_ALTDIRFUNC,
+ "dir1lev1/dir1lev2/.",
+ "dir1lev1/dir1lev2/..",
+ "dir1lev1/dir2lev2/.",
+ "dir1lev1/dir2lev2/..",
+ "dir1lev1/dir2lev2/.foo",
+ "dir1lev1/dir3lev2/.",
+ "dir1lev1/dir3lev2/..",
+ "dir2lev1/dir1lev2/.",
+ "dir2lev1/dir1lev2/..",
+ "dir2lev1/dir1lev2/.dir",
+ "dir2lev1/dir1lev2/.foo");
+
+ test ("*1*/*1*/.*", GLOB_ALTDIRFUNC,
+ "dir1lev1/dir1lev2/.",
+ "dir1lev1/dir1lev2/..",
+ "dir2lev1/dir1lev2/.",
+ "dir2lev1/dir1lev2/..",
+ "dir2lev1/dir1lev2/.dir",
+ "dir2lev1/dir1lev2/.foo");
+
+ globfree (&gl);
+
+ return result;
+}
+
+#else
+int main(void) { return 0; }
+#endif
diff --git a/test/misc/tst-inotify.c b/test/misc/tst-inotify.c
new file mode 100644
index 0000000..f9f6830
--- /dev/null
+++ b/test/misc/tst-inotify.c
@@ -0,0 +1,65 @@
+/* vi: set sw=4 ts=4 sts=4: */
+/*
+ * inotify test for uClibc
+ * Copyright (C) 2012 by Kevin Cernekee <cernekee@gmail.com>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <sys/inotify.h>
+#include <sys/fcntl.h>
+
+static int
+do_test(void)
+{
+ int ifd, fd, ret, result = 0;
+ struct inotify_event e;
+ char tfile[] = "/tmp/inotify.XXXXXX";
+
+ fd = mkstemp(tfile);
+ close(fd);
+
+ ifd = inotify_init1(IN_NONBLOCK);
+ if (ifd < 0) {
+ perror("inotify_init1()");
+ result = 1;
+ }
+ if (inotify_add_watch(ifd, tfile, IN_DELETE_SELF) < 0) {
+ perror("inotify_add_watch()");
+ result = 1;
+ }
+
+ /* nonblocking inotify should return immediately with no events */
+ ret = read(ifd, &e, sizeof(e));
+ if (ret != -1 || errno != EAGAIN) {
+ fprintf(stderr, "first read() returned %d\n", ret);
+ result = 1;
+ }
+
+ /* generate an event */
+ unlink(tfile);
+
+ /* now check whether our event was seen */
+ ret = read(ifd, &e, sizeof(e));
+ if (ret != sizeof(e)) {
+ fprintf(stderr, "second read() returned %d\n", ret);
+ result = 1;
+ }
+
+ if (!(e.mask & IN_DELETE_SELF)) {
+ fprintf(stderr, "incorrect event mask: %" PRIx32 "\n", e.mask);
+ result = 1;
+ }
+
+ return result;
+}
+
+#define TIMEOUT 5
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/misc/tst-mkostemps.c b/test/misc/tst-mkostemps.c
new file mode 100644
index 0000000..272e747
--- /dev/null
+++ b/test/misc/tst-mkostemps.c
@@ -0,0 +1,159 @@
+/*
+ * Test application for mkstemp/mkstemps/mkostemp/mkostemps
+ * Copyright (C) 2015 by Romain Naour <romain.naour@openwide.fr>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#define assert(x) \
+ if (!(x)) \
+ { \
+ fputs ("test failed: " #x "\n", stderr); \
+ retval = 1; \
+ goto the_end; \
+ }
+
+int
+main (int argc, char *argv[])
+{
+ char name[256];
+ char name_suffix[256];
+ FILE *fp = NULL;
+ int retval = 0;
+ int fd;
+ int flags = O_RDONLY | O_CLOEXEC;
+ struct stat sb_f1;
+ struct stat sb_f2;
+
+ /* mkstemp test */
+ sprintf(name, "/tmp/%s-uClibc-test.XXXXXX", __FILE__);
+
+ fd = mkstemp(name);
+
+ fstat(fd, &sb_f1);
+ assert ((sb_f1.st_mode & S_IFMT) == S_IFREG)
+
+ stat(name, &sb_f2);
+ assert ((sb_f2.st_mode & S_IFMT) == S_IFREG)
+
+ assert (sb_f1.st_ino == sb_f2.st_ino)
+
+ close(fd);
+ unlink (name);
+
+ /* mkstemps test */
+ sprintf(name_suffix, "/tmp/%s-uClibc-test.XXXXXX.txt", __FILE__);
+
+ fd = mkstemps(name_suffix, 4);
+
+ fstat(fd, &sb_f1);
+ assert ((sb_f1.st_mode & S_IFMT) == S_IFREG)
+
+ stat(name_suffix, &sb_f2);
+ assert ((sb_f2.st_mode & S_IFMT) == S_IFREG)
+
+ assert (sb_f1.st_ino == sb_f2.st_ino)
+
+ close(fd);
+ unlink (name_suffix);
+
+ /* mkostemp test */
+ sprintf(name, "/tmp/%s-uClibc-test.XXXXXX", __FILE__);
+
+ fd = mkostemp(name, flags);
+
+ fstat(fd, &sb_f1);
+ assert ((sb_f1.st_mode & S_IFMT) == S_IFREG)
+
+ stat(name, &sb_f2);
+ assert ((sb_f2.st_mode & S_IFMT) == S_IFREG)
+
+ assert (sb_f1.st_ino == sb_f2.st_ino)
+ assert (sb_f1.st_mode == sb_f2.st_mode)
+
+ close(fd);
+ unlink (name);
+
+ /* mkostemps test */
+ sprintf(name_suffix, "/tmp/%s-uClibc-test.XXXXXX.txt", __FILE__);
+
+ fd = mkostemps(name_suffix, 4, flags);
+
+ fstat(fd, &sb_f1);
+ assert ((sb_f1.st_mode & S_IFMT) == S_IFREG)
+
+ stat(name_suffix, &sb_f2);
+ assert ((sb_f2.st_mode & S_IFMT) == S_IFREG)
+
+ assert (sb_f1.st_ino == sb_f2.st_ino)
+ assert (sb_f1.st_mode == sb_f2.st_mode)
+
+ close(fd);
+ unlink (name_suffix);
+
+ /* suffixlen = 0 */
+ sprintf(name_suffix, "/tmp/%s-uClibc-test.XXXXXX", __FILE__);
+
+ fd = mkostemps(name_suffix, 0, flags);
+
+ fstat(fd, &sb_f1);
+ assert ((sb_f1.st_mode & S_IFMT) == S_IFREG)
+
+ stat(name_suffix, &sb_f2);
+ assert ((sb_f2.st_mode & S_IFMT) == S_IFREG)
+
+ assert (sb_f1.st_ino == sb_f2.st_ino)
+ assert (sb_f1.st_mode == sb_f2.st_mode)
+
+ close(fd);
+ unlink (name_suffix);
+
+ /* stress tests */
+
+ /* template len < 6 */
+ sprintf(name, "XXXXX");
+
+ fd = mkstemp(name);
+
+ assert(fd == -1);
+ assert(errno == EINVAL);
+
+ /* suffixlen < 0 */
+ sprintf(name_suffix, "/tmp/%s-uClibc-test.XXXXXX.txt", __FILE__);
+
+ fd = mkostemps(name_suffix, -1, flags);
+
+ assert(fd == -1);
+ assert(errno == EINVAL);
+
+ /* Missing one X */
+ sprintf(name_suffix, "/tmp/%s-uClibc-test.XXXXX.txt", __FILE__);
+
+ fd = mkostemps(name_suffix, 4, flags);
+
+ assert(fd == -1);
+ assert(errno == EINVAL);
+
+ /* wrong suffixlen */
+ sprintf(name_suffix, "/tmp/%s-uClibc-test.XXXXXX.txt", __FILE__);
+
+ fd = mkostemps(name_suffix, 2, flags);
+
+ assert(fd == -1);
+ assert(errno == EINVAL);
+
+the_end:
+ if (fp != NULL)
+ assert (fclose (fp) == 0);
+ unlink (name);
+ unlink (name_suffix);
+
+ return retval;
+}
diff --git a/test/misc/tst-nftw.c b/test/misc/tst-nftw.c
new file mode 100644
index 0000000..76d11eb
--- /dev/null
+++ b/test/misc/tst-nftw.c
@@ -0,0 +1,57 @@
+#define _XOPEN_SOURCE 500
+#define _GNU_SOURCE
+#include <ftw.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+int result = 0;
+
+static int process_one_entry(const char *fpath, const struct stat *sb,
+ int typeflag, struct FTW *ftwbuf)
+{
+
+ struct stat buf;
+ const char *rel_path = fpath+ftwbuf->base;
+
+ printf("Processing %s in working dir %s\n",
+ rel_path, get_current_dir_name());
+ if (stat(rel_path, &buf) < 0) {
+ perror("Oops...relative path does not exist in current directory");
+ result = 1;
+ }
+}
+
+static int
+do_test(void)
+{
+ char *path = "/tmp/stest_dir";
+ char *subpath = "/tmp/stest_dir/d1";
+ char *filepath = "/tmp/stest_dir/f1";
+ char *filesubpath = "/tmp/stest_dir/d1/f2";
+
+ if ((mkdir(path, 0700)) < 0)
+ perror("Creating path");
+ if ((mkdir(subpath, 0700)) < 0)
+ perror("Creating subpath");
+ if ((open(filepath, O_CREAT)) < 0)
+ perror("Opening filepath");
+ if ((open(filesubpath, O_CREAT)) < 0)
+ perror("Opening filesubpath");
+
+ if (nftw(path, process_one_entry, 100, (FTW_CHDIR|FTW_DEPTH|FTW_PHYS)) < 0)
+ perror("ntfw");
+
+ unlink(filesubpath);
+ unlink(filepath);
+ rmdir(subpath);
+ rmdir(path);
+
+ return result;
+}
+
+#define TIMEOUT 5
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/misc/tst-scandir.c b/test/misc/tst-scandir.c
new file mode 100644
index 0000000..e1c72e3
--- /dev/null
+++ b/test/misc/tst-scandir.c
@@ -0,0 +1,23 @@
+#include <dirent.h>
+#include <errno.h>
+#include <stdio.h> /* perror() */
+#include <stdlib.h>
+
+static int skip_all(const struct dirent *dirbuf)
+{
+ errno = EBADF;
+ return 0;
+}
+
+int main(void)
+{
+ struct dirent **namelist;
+ int n;
+
+ n = scandir(".", &namelist, skip_all, 0);
+ if (n < 0) {
+ perror("scandir");
+ return EXIT_FAILURE;
+ }
+ return EXIT_SUCCESS;
+}
diff --git a/test/misc/tst-seekdir.c b/test/misc/tst-seekdir.c
new file mode 100644
index 0000000..7dd5d2e
--- /dev/null
+++ b/test/misc/tst-seekdir.c
@@ -0,0 +1,79 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <dirent.h>
+#include <stdlib.h>
+
+int
+main (int argc, char *argv[])
+{
+ DIR * dirp;
+ long int save3 = 0;
+ long int cur;
+ int i = 0;
+ int result = 0;
+ struct dirent *dp;
+ off_t save0, rewind_ret;
+
+ dirp = opendir (".");
+ if (dirp == NULL)
+ {
+ printf ("opendir failed: %s\n", strerror(errno));
+ return 1;
+ }
+
+ save0 = telldir (dirp);
+ if (save0 == -1)
+ {
+ printf ("telldir failed: %s\n", strerror(errno));
+ result = 1;
+ }
+
+ for (dp = readdir (dirp); dp != NULL; dp = readdir (dirp))
+ {
+ /* save position 3 (after fourth entry) */
+ if (i++ == 3)
+ save3 = telldir (dirp);
+
+ printf ("%s\n", dp->d_name);
+
+ /* stop at 400 (just to make sure dirp->__offset and dirp->__size are
+ scrambled */
+ if (i == 400)
+ break;
+ }
+
+ printf ("going back past 4-th entry...\n");
+
+ /* go back to saved entry */
+ seekdir (dirp, save3);
+
+ /* Check whether telldir equals to save3 now. */
+ cur = telldir (dirp);
+ if (cur != save3)
+ {
+ printf ("seekdir (d, %ld); telldir (d) == %ld\n", save3, cur);
+ result = 1;
+ }
+
+ /* print remaining files (3-last) */
+ for (dp = readdir (dirp); dp != NULL; dp = readdir (dirp))
+ printf ("%s\n", dp->d_name);
+
+ /* Check rewinddir */
+ rewinddir (dirp);
+ rewind_ret = telldir (dirp);
+ if (rewind_ret == -1)
+ {
+ printf ("telldir failed: %s\n", strerror(errno));
+ result = 1;
+ }
+ else if (save0 != rewind_ret)
+ {
+ printf ("rewinddir didn't reset directory stream\n");
+ result = 1;
+ }
+
+ closedir (dirp);
+ return result;
+}
diff --git a/test/misc/tst-statfs.c b/test/misc/tst-statfs.c
new file mode 100644
index 0000000..b8b4229
--- /dev/null
+++ b/test/misc/tst-statfs.c
@@ -0,0 +1,31 @@
+#include <sys/vfs.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int
+main(int argc, char* argv[])
+{
+ struct statfs s;
+ int ret = 0, i;
+
+ for (i = 1; i < argc; i++) {
+ if (statfs(argv[i], &s) != 0) {
+ fprintf(stderr, "%s: %s: statfs failed. %s\n",
+ *argv, argv[i], strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ ++ret;
+ printf("statfs %s:\n\tblocks=%lld\n\tblkfree=%lld\n\tbsize=%d\n",
+ argv[i], s.f_blocks, s.f_bfree, s.f_bsize);
+#ifdef _STATFS_F_FRSIZE
+ printf("\tfrsize=%lld\n", s.f_frsize);
+#elif defined __mips__
+ printf("\tfrsize=mips, unsupported?\n");
+#else
+# error no _STATFS_F_FRSIZE
+#endif
+ }
+ exit(ret ? EXIT_SUCCESS : EXIT_FAILURE);
+}
diff --git a/test/misc/tst-statvfs.c b/test/misc/tst-statvfs.c
new file mode 100644
index 0000000..4b67719
--- /dev/null
+++ b/test/misc/tst-statvfs.c
@@ -0,0 +1,26 @@
+#include <sys/statvfs.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int
+main(int argc, char* argv[])
+{
+ struct statvfs s;
+ int i;
+
+ for (i = 1; i < argc; i++) {
+ if (statvfs(argv[i], &s) != 0) {
+ fprintf(stderr, "%s: %s: statvfs failed. %s\n",
+ *argv, argv[i], strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ printf("statvfs %s:\n\tblocks=%lld\n\tblkfree=%lld\n\tbsize=%d\n",
+ argv[i], s.f_blocks, s.f_bfree, s.f_bsize);
+#if 1 // def _STATFS_F_FRSIZE
+ printf("\tfrsize=%lld\n", s.f_frsize);
+#endif
+ }
+ exit(EXIT_SUCCESS);
+}
diff --git a/test/misc/tst-utmp.c b/test/misc/tst-utmp.c
new file mode 100644
index 0000000..1b0333a
--- /dev/null
+++ b/test/misc/tst-utmp.c
@@ -0,0 +1,423 @@
+/* Tests for UTMP functions.
+ Copyright (C) 1998, 2001-2003 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 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 <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <time.h>
+
+#ifdef UTMPX
+# include <utmpx.h>
+# define utmp utmpx
+# define utmpname utmpxname
+# define setutent setutxent
+# define getutent getutxent
+# define endutent endutxent
+# define getutline getutxline
+# define getutid getutxid
+# define pututline pututxline
+#else
+# include <utmp.h>
+#endif
+
+#ifndef _HAVE_UT_TYPE
+# define _HAVE_UT_TYPE 0
+#endif
+#ifndef _HAVE_UT_PID
+# define _HAVE_UT_PID 0
+#endif
+#ifndef _HAVE_UT_ID
+# define _HAVE_UT_ID 0
+#endif
+#ifndef _HAVE_UT_TV
+# define _HAVE_UT_TV 0
+#endif
+#ifndef _HAVE_UT_HOST
+# define _HAVE_UT_HOST 0
+#endif
+
+#if _HAVE_UT_TYPE || defined UTMPX
+
+/* Prototype for our test function. */
+static int do_test (int argc, char *argv[]);
+
+/* We have a preparation function. */
+static void do_prepare (int argc, char *argv[]);
+#define PREPARE do_prepare
+
+/* This defines the `main' function and some more. */
+#include "../test-skeleton.c"
+
+
+/* These are for the temporary file we generate. */
+char *name;
+int fd;
+
+static void
+do_prepare (int argc, char *argv[])
+{
+ size_t name_len;
+
+ name_len = strlen (test_dir);
+ name = malloc (name_len + sizeof ("/utmpXXXXXX"));
+ mempcpy (mempcpy (name, test_dir, name_len),
+ "/utmpXXXXXX", sizeof ("/utmpXXXXXX"));
+ add_temp_file (name);
+
+ /* Open our test file. */
+ fd = mkstemp (name);
+ if (fd == -1) {
+ fprintf (stderr, "cannot open test file `%s': ", name);
+ perror (NULL);
+ exit (EXIT_FAILURE);
+ }
+}
+
+struct utmp entry[] =
+{
+#if _HAVE_UT_TV || defined UTMPX
+#define UT(a) .ut_tv = { .tv_sec = (a)}
+#else
+#define UT(a) .ut_time = (a)
+#endif
+
+ { .ut_type = BOOT_TIME, .ut_pid = 1, UT(1000) },
+ { .ut_type = RUN_LVL, .ut_pid = 1, UT(2000) },
+ { .ut_type = INIT_PROCESS, .ut_pid = 5, .ut_id = "si", UT(3000) },
+ { .ut_type = LOGIN_PROCESS, .ut_pid = 23, .ut_line = "tty1", .ut_id = "1",
+ .ut_user = "LOGIN", UT(4000) },
+ { .ut_type = USER_PROCESS, .ut_pid = 24, .ut_line = "tty2", .ut_id = "2",
+ .ut_user = "albert", UT(8000) },
+ { .ut_type = USER_PROCESS, .ut_pid = 196, .ut_line = "ttyp0", .ut_id = "p0",
+ .ut_user = "niels", UT(10000) },
+ { .ut_type = DEAD_PROCESS, .ut_line = "ttyp1", .ut_id = "p1", UT(16000) },
+ { .ut_type = EMPTY },
+ { .ut_type = EMPTY }
+};
+int num_entries = sizeof entry / sizeof (struct utmp);
+
+time_t entry_time = 20000;
+pid_t entry_pid = 234;
+
+static int
+do_init (void)
+{
+ int n;
+
+ setutent ();
+
+ for (n = 0; n < num_entries; n++)
+ {
+ if (pututline (&entry[n]) == NULL)
+ {
+ perror ("cannot write UTMP entry");
+ return 1;
+ }
+ }
+
+ endutent ();
+
+ return 0;
+}
+
+
+static int
+do_check (void)
+{
+ struct utmp *ut;
+ int n;
+
+ setutent ();
+
+ n = 0;
+ while ((ut = getutent ()))
+ {
+ if (n < num_entries &&
+ memcmp (ut, &entry[n], sizeof (struct utmp)))
+ {
+ fprintf (stderr, "UTMP entry does not match\n");
+ return 1;
+ }
+
+ n++;
+ }
+
+ if (n != num_entries)
+ {
+ fprintf (stderr, "number of UTMP entries is incorrect\n");
+ return 1;
+ }
+
+ endutent ();
+
+ return 0;
+}
+
+static int
+simulate_login (const char *line, const char *user)
+{
+ int n;
+
+ for (n = 0; n < num_entries; n++)
+ {
+ if (strcmp (line, entry[n].ut_line) == 0 ||
+ entry[n].ut_type == DEAD_PROCESS)
+ {
+ if (entry[n].ut_pid == DEAD_PROCESS)
+ entry[n].ut_pid = (entry_pid += 27);
+ entry[n].ut_type = USER_PROCESS;
+ strncpy (entry[n].ut_user, user, sizeof (entry[n].ut_user));
+#if _HAVE_UT_TV - 0 || defined UTMPX
+ entry[n].ut_tv.tv_sec = (entry_time += 1000);
+#else
+ entry[n].ut_time = (entry_time += 1000);
+#endif
+ setutent ();
+
+ if (pututline (&entry[n]) == NULL)
+ {
+ perror ("cannot write UTMP entry");
+ return 1;
+ }
+
+ endutent ();
+
+ return 0;
+ }
+ }
+
+ fprintf (stderr, "no entries available\n");
+ return 1;
+}
+
+static int
+simulate_logout (const char *line)
+{
+ int n;
+
+ for (n = 0; n < num_entries; n++)
+ {
+ if (strcmp (line, entry[n].ut_line) == 0)
+ {
+ entry[n].ut_type = DEAD_PROCESS;
+ strncpy (entry[n].ut_user, "", sizeof (entry[n].ut_user));
+#if _HAVE_UT_TV - 0 || defined UTMPX
+ entry[n].ut_tv.tv_sec = (entry_time += 1000);
+#else
+ entry[n].ut_time = (entry_time += 1000);
+#endif
+ setutent ();
+
+ if (pututline (&entry[n]) == NULL)
+ {
+ perror ("cannot write UTMP entry");
+ return 1;
+ }
+
+ endutent ();
+
+ return 0;
+ }
+ }
+
+ fprintf (stderr, "no entry found for `%s'\n", line);
+ return 1;
+}
+
+static int
+check_login (const char *line)
+{
+ struct utmp *up;
+ struct utmp ut;
+ int n;
+
+ setutent ();
+
+ strcpy (ut.ut_line, line);
+ up = getutline (&ut);
+ if (up == NULL)
+ {
+ fprintf (stderr, "cannot get entry for line `%s': ", line);
+ perror(NULL);
+ return 1;
+ }
+
+ endutent ();
+
+ for (n = 0; n < num_entries; n++)
+ {
+ if (strcmp (line, entry[n].ut_line) == 0)
+ {
+ if (memcmp (up, &entry[n], sizeof (struct utmp)))
+ {
+ fprintf (stderr, "UTMP entry does not match\n");
+ return 1;
+ }
+
+ return 0;
+ }
+ }
+
+ fprintf (stderr, "bogus entry for line `%s'\n", line);
+ return 1;
+}
+
+static int
+check_logout (const char *line)
+{
+ struct utmp ut;
+
+ setutent ();
+
+ strcpy (ut.ut_line, line);
+ if (getutline (&ut) != NULL)
+ {
+ fprintf (stderr, "bogus login entry for `%s'\n", line);
+ return 1;
+ }
+
+ endutent ();
+
+ return 0;
+}
+
+static int
+check_id (const char *id)
+{
+ struct utmp *up;
+ struct utmp ut;
+ int n;
+
+ setutent ();
+
+ ut.ut_type = USER_PROCESS;
+ strcpy (ut.ut_id, id);
+ up = getutid (&ut);
+ if (up == NULL)
+ {
+ fprintf (stderr, "cannot get entry for ID `%s': ", id);
+ perror (NULL);
+ return 1;
+ }
+
+ endutent ();
+
+ for (n = 0; n < num_entries; n++)
+ {
+ if (strcmp (id, entry[n].ut_id) == 0)
+ {
+ if (memcmp (up, &entry[n], sizeof (struct utmp)))
+ {
+ fprintf (stderr, "UTMP entry does not match\n");
+ return 1;
+ }
+
+ return 0;
+ }
+ }
+
+ fprintf (stderr, "bogus entry for ID `%s'\n", id);
+ return 1;
+}
+
+static int
+check_type (int type)
+{
+ struct utmp *up;
+ struct utmp ut;
+ int n;
+
+ setutent ();
+
+ ut.ut_type = type;
+ up = getutid (&ut);
+ if (up == NULL)
+ {
+ fprintf (stderr, "cannot get entry for type `%d': ", type);
+ perror (NULL);
+ return 1;
+ }
+
+ endutent ();
+
+ for (n = 0; n < num_entries; n++)
+ {
+ if (type == entry[n].ut_type)
+ {
+ if (memcmp (up, &entry[n], sizeof (struct utmp)))
+ {
+ fprintf (stderr, "UTMP entry does not match\n");
+ return 1;
+ }
+
+ return 0;
+ }
+ }
+
+ fprintf (stderr, "bogus entry for type `%d'\n", type);
+ return 1;
+}
+
+static int
+do_test (int argc, char *argv[])
+{
+ int result = 0;
+
+ utmpname (name);
+
+ result |= do_init ();
+ result |= do_check ();
+
+ result |= simulate_login ("tty1", "erwin");
+ result |= do_check ();
+
+ result |= simulate_login ("ttyp1", "paul");
+ result |= do_check ();
+
+ result |= simulate_logout ("tty2");
+ result |= do_check ();
+
+ result |= simulate_logout ("ttyp0");
+ result |= do_check ();
+
+ result |= simulate_login ("ttyp2", "richard");
+ result |= do_check ();
+
+ result |= check_login ("tty1");
+ result |= check_logout ("ttyp0");
+ result |= check_id ("p1");
+ result |= check_id ("2");
+ result |= check_id ("si");
+ result |= check_type (BOOT_TIME);
+ result |= check_type (RUN_LVL);
+
+ return result;
+}
+
+#else
+
+/* No field 'ut_type' in struct utmp. */
+int
+main ()
+{
+ return 0;
+}
+
+#endif
diff --git a/test/misc/tst-utmpx.c b/test/misc/tst-utmpx.c
new file mode 100644
index 0000000..edb5551
--- /dev/null
+++ b/test/misc/tst-utmpx.c
@@ -0,0 +1,2 @@
+#define UTMPX
+#include "tst-utmp.c"