summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2011-03-19 22:26:06 -0400
committerRich Felker <dalias@aerifal.cx>2011-03-19 22:26:06 -0400
commita9baddd7d07b9fe15e212985a808a79773ec72e4 (patch)
treefce0a089eedeacef8b25b409c2ba50f5f30a8327
downloadlibc-testsuite-a9baddd7d07b9fe15e212985a808a79773ec72e4.tar.gz
initial check-in, taken from old libc svn repo with significant additions
-rw-r--r--Makefile29
-rw-r--r--README32
-rw-r--r--basename.c30
-rw-r--r--config.mak3
-rw-r--r--dirname.c32
-rw-r--r--env.c40
-rw-r--r--fdopen.c40
-rw-r--r--fnmatch.c142
-rw-r--r--fscanf.c47
-rw-r--r--hello.old308
-rw-r--r--mbc.c92
-rw-r--r--popen.c51
-rw-r--r--pthread.c161
-rw-r--r--qsort.c59
-rw-r--r--sem.c52
-rw-r--r--snprintf.c120
-rw-r--r--sscanf.c90
-rw-r--r--string.c118
-rw-r--r--strtod.c40
-rw-r--r--strtol.c86
-rw-r--r--testsuite.c38
-rw-r--r--time.c76
-rw-r--r--ungetc.c55
-rw-r--r--wcstol.c78
24 files changed, 1819 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..5cccb18
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,29 @@
+
+SRCS = $(wildcard *.c)
+OBJS = $(SRCS:.c=.o)
+
+CFLAGS = -std=c99 -Os -fno-builtin -D_XOPEN_SOURCE=700
+LDFLAGS = -static
+LIBS = -lrt -lpthread -lrt -lm
+
+-include config.mak
+
+all: testsuite
+
+testsuite: $(OBJS)
+ $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
+
+%.o: %.c
+ $(CC) $(CFLAGS) -o $@ -c $<
+
+clean:
+ rm -f $(OBJS) testsuite
+
+relink:
+ rm -f testsuite
+ make all
+
+test: testsuite
+ ./testsuite
+
+retest: relink test
diff --git a/README b/README
new file mode 100644
index 0000000..bcf993a
--- /dev/null
+++ b/README
@@ -0,0 +1,32 @@
+
+libc-testsuite README
+
+
+This package is a collection of unit tests to measure the correctness
+and robustness of a C/POSIX standard library implementation. It was
+developed as a tool for testing musl and its first-generation
+predecessor. As such, most of the tests were written to be
+self-contained and not to make assumptions about other library
+interfaces being present or working correctly.
+
+At present the whole testsuite builds as a single binary and runs as a
+single process (aside from a few child processes that are part of the
+tests). This makes it extremely fast, but also means that corruption
+of the global state due to bugs in one set of interfaces may affect
+later tests. If necessary, the main test dispatch module could be
+modified to fork before running each test, ensuring that each one
+begins with a clean working state.
+
+
+Building and running the tests
+
+If needed, a file named config.mak can be created to override the
+default CC, CFLAGS, etc. used by the build process. Otherwise, simply
+run "make" in the libc-testsuite directory to build the tests. Then
+run "./testsuite" or "make test" to run the tests.
+
+The following additional CFLAGS options may be of interest:
+
+-DHAVE_BSD_STRL - tests the BSD strlcpy and strlcat functions.
+-DDISABLE_SLOW_TESTS - disables testing 2GB snprintf.
+
diff --git a/basename.c b/basename.c
new file mode 100644
index 0000000..2f0ee2a
--- /dev/null
+++ b/basename.c
@@ -0,0 +1,30 @@
+#include <stdio.h>
+#include <string.h>
+#include <libgen.h>
+#include <stdlib.h>
+
+#define TEST(p, b) ( \
+tmp = strdup((p)), s = basename(tmp), \
+!strcmp((b),s) || \
+(printf(__FILE__ ":%d: basename(\"%s\") returned \"%s\"; expected \"%s\"\n", \
+__LINE__, (p), s, (b)), err++, 0), free(tmp), 0 )
+
+int test_basename(void)
+{
+ char *tmp, *s;
+ int err=0;
+
+ if (strcmp(basename(NULL), ".")) {
+ printf(__FILE__ ":%d: basename(NULL) returned \"%s\"; "
+ "expected \".\"\n", __LINE__, basename(NULL));
+ err++;
+ }
+ TEST("", ".");
+ TEST("/usr/lib", "lib");
+ TEST("/usr/", "usr");
+ TEST("/", "/");
+ TEST("///", "/");
+ TEST("//usr//lib//", "lib");
+
+ return err;
+}
diff --git a/config.mak b/config.mak
new file mode 100644
index 0000000..7be2b3a
--- /dev/null
+++ b/config.mak
@@ -0,0 +1,3 @@
+CFLAGS += -Wall -Wno-overflow -Wno-unused -Wno-format
+CFLAGS += -DHAVE_BSD_STRL
+CFLAGS += -DDISABLE_SLOW_TESTS
diff --git a/dirname.c b/dirname.c
new file mode 100644
index 0000000..761512a
--- /dev/null
+++ b/dirname.c
@@ -0,0 +1,32 @@
+#include <stdio.h>
+#include <string.h>
+#include <libgen.h>
+#include <stdlib.h>
+
+#define TEST(p, b) ( \
+tmp = strdup((p)), s = dirname(tmp), \
+!strcmp((b),s) || \
+(printf(__FILE__ ":%d: dirname(\"%s\") returned \"%s\"; expected \"%s\"\n", \
+__LINE__, (p), s, (b)), err++, 0), free(tmp), 0 )
+
+int test_dirname(void)
+{
+ char *tmp, *s;
+ int err=0;
+
+ if (strcmp(dirname(NULL), ".")) {
+ printf(__FILE__ ":%d: dirname(NULL) returned \"%s\"; "
+ "expected \".\"\n", __LINE__, dirname(NULL));
+ err++;
+ }
+ TEST("", ".");
+ TEST("/usr/lib", "/usr");
+ TEST("/usr/", "/");
+ TEST("usr", ".");
+ TEST("/", "/");
+ TEST("///", "/");
+ TEST(".", ".");
+ TEST("..", ".");
+
+ return err;
+}
diff --git a/env.c b/env.c
new file mode 100644
index 0000000..3214ed2
--- /dev/null
+++ b/env.c
@@ -0,0 +1,40 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#define TEST(r, f, x, m) ( \
+((r) = (f)) == (x) || \
+(printf(__FILE__ ":%d: %s failed (" m ")\n", __LINE__, #f, r, x, strerror(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) )
+
+extern char **environ;
+int clearenv(void);
+
+int test_env(void)
+{
+ int i;
+ int err=0;
+ char a[100], b[100], *s;
+ FILE *f;
+
+ TEST(i, (clearenv(), !environ || !*environ), 1, "failed");
+ TEST(i, putenv("TEST=1"), 0, "failed");
+ TEST(s, environ[1], 0, "%p != 0");
+ TEST_S((s=getenv("TEST")), "1", "failed");
+ TEST(i, unsetenv("TEST"), 0, "failed");
+ TEST(i, !*environ, 1, "failed");
+ TEST(i, setenv("TEST", "2", 0), 0, "failed");
+ TEST_S((s=getenv("TEST")), "2", "failed");
+ TEST(i, setenv("TEST", "3", 0), 0, "failed");
+ TEST_S((s=getenv("TEST")), "2", "failed");
+ TEST(i, setenv("TEST", "3", 1), 0, "failed");
+ TEST_S((s=getenv("TEST")), "3", "failed");
+
+ return err;
+}
diff --git a/fdopen.c b/fdopen.c
new file mode 100644
index 0000000..bbd3af7
--- /dev/null
+++ b/fdopen.c
@@ -0,0 +1,40 @@
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.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) )
+
+int test_fdopen(void)
+{
+ char tmp[] = "/tmp/testsuite-XXXXXX";
+ char foo[6];
+ int fd;
+ int err = 0;
+ FILE *f;
+
+ TEST_E((fd = mkstemp(tmp)) > 2);
+ TEST_E(write(fd, "hello", 6)==6);
+ TEST_E(f = fdopen(fd, "rb"));
+ if (f) {
+ TEST_E(ftello(f)==6);
+ TEST_E(fseeko(f, 0, SEEK_SET)==0);
+ TEST_E(fgets(foo, sizeof foo, f));
+ TEST_S(foo, "hello", "fgets read back wrong message");
+ fclose(f);
+ }
+
+ if (fd > 2) TEST_E(unlink(tmp) != -1);
+
+ return err;
+}
diff --git a/fnmatch.c b/fnmatch.c
new file mode 100644
index 0000000..0ab8ffb
--- /dev/null
+++ b/fnmatch.c
@@ -0,0 +1,142 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <fnmatch.h>
+#include <unistd.h>
+
+/* adapted from dietlibc's test-newfnmatch.c */
+
+/*
+ * xlat / printflags adapted from strace
+ * http://www.liacs.nl/~wichert/strace/
+ */
+
+#define FLAG(f) { f, #f }
+
+struct xlat {
+ int val;
+ char *str;
+} fnmatch_flags[] = {
+ FLAG(FNM_NOESCAPE),
+ FLAG(FNM_PATHNAME),
+ FLAG(FNM_PERIOD),
+ {0, NULL},
+};
+
+static void printflags(const struct xlat *map, int flags) {
+ char * sep;
+
+ if (! flags) {
+ printf("0");
+ return;
+ }
+
+ sep = "";
+ for (; map->str; map++) {
+ if (map->val && (flags & map->val) == map->val) {
+ printf("%s%s", sep, map->str);
+ sep = "|";
+ flags &= ~(map->val);
+ }
+ }
+ if (flags) printf("%sunknown=%#x", sep, flags);
+}
+
+/*
+ * tests harness adapted from glibc testfnm.c
+ */
+struct {
+ const char *pattern;
+ const char *string;
+ int flags;
+ int expected;
+} tests[] = {
+ /* begin dietlibc tests */
+ { "*.c", "foo.c", 0, 0 },
+ { "*.c", ".c", 0, 0 },
+ { "*.a", "foo.c", 0, FNM_NOMATCH },
+ { "*.c", ".foo.c", 0, 0 },
+ { "*.c", ".foo.c", FNM_PERIOD, FNM_NOMATCH },
+ { "*.c", "foo.c", FNM_PERIOD, 0 },
+ { "a\\*.c", "a*.c", FNM_NOESCAPE, FNM_NOMATCH },
+ { "a\\*.c", "ax.c", 0, FNM_NOMATCH },
+ { "a[xy].c", "ax.c", 0, 0 },
+ { "a[!y].c", "ax.c", 0, 0 },
+ { "a[a/z]*.c", "a/x.c", FNM_PATHNAME, FNM_NOMATCH },
+ { "a/*.c", "a/x.c", FNM_PATHNAME, 0 },
+ { "a*.c", "a/x.c", FNM_PATHNAME, FNM_NOMATCH },
+ { "*/foo", "/foo", FNM_PATHNAME, 0 },
+ { "-O[01]", "-O1", 0, 0 },
+ { "[[?*\\]", "\\", 0, 0 },
+ { "[]?*\\]", "]", 0, 0 },
+ /* initial right-bracket tests */
+ { "[!]a-]", "b", 0, 0 },
+ { "[]-_]", "^", 0, 0 }, /* range: ']', '^', '_' */
+ { "[!]-_]", "X", 0, 0 },
+ { "??", "-", 0, FNM_NOMATCH },
+ /* begin glibc tests */
+ { "*LIB*", "lib", FNM_PERIOD, FNM_NOMATCH },
+ { "a[/]b", "a/b", 0, 0 },
+ { "a[/]b", "a/b", FNM_PATHNAME, FNM_NOMATCH },
+ { "[a-z]/[a-z]", "a/b", 0, 0 },
+ { "*", "a/b", FNM_PATHNAME, FNM_NOMATCH },
+ { "*[/]b", "a/b", FNM_PATHNAME, FNM_NOMATCH },
+ { "*[b]", "a/b", FNM_PATHNAME, FNM_NOMATCH },
+ { "[*]/b", "a/b", 0, FNM_NOMATCH },
+ { "[*]/b", "*/b", 0, 0 },
+ { "[?]/b", "a/b", 0, FNM_NOMATCH },
+ { "[?]/b", "?/b", 0, 0 },
+ { "[[a]/b", "a/b", 0, 0 },
+ { "[[a]/b", "[/b", 0, 0 },
+ { "\\*/b", "a/b", 0, FNM_NOMATCH },
+ { "\\*/b", "*/b", 0, 0 },
+ { "\\?/b", "a/b", 0, FNM_NOMATCH },
+ { "\\?/b", "?/b", 0, 0 },
+ { "[/b", "[/b", 0, -FNM_NOMATCH },
+ { "\\[/b", "[/b", 0, 0 },
+ { "??""/b", "aa/b", 0, 0 },
+ { "???b", "aa/b", 0, 0 },
+ { "???b", "aa/b", FNM_PATHNAME, FNM_NOMATCH },
+ { "?a/b", ".a/b", FNM_PATHNAME|FNM_PERIOD, FNM_NOMATCH },
+ { "a/?b", "a/.b", FNM_PATHNAME|FNM_PERIOD, FNM_NOMATCH },
+ { "*a/b", ".a/b", FNM_PATHNAME|FNM_PERIOD, FNM_NOMATCH },
+ { "a/*b", "a/.b", FNM_PATHNAME|FNM_PERIOD, FNM_NOMATCH },
+ { "[.]a/b", ".a/b", FNM_PATHNAME|FNM_PERIOD, FNM_NOMATCH },
+ { "a/[.]b", "a/.b", FNM_PATHNAME|FNM_PERIOD, FNM_NOMATCH },
+ { "*/?", "a/b", FNM_PATHNAME|FNM_PERIOD, 0 },
+ { "?/*", "a/b", FNM_PATHNAME|FNM_PERIOD, 0 },
+ { ".*/?", ".a/b", FNM_PATHNAME|FNM_PERIOD, 0 },
+ { "*/.?", "a/.b", FNM_PATHNAME|FNM_PERIOD, 0 },
+ { "*/*", "a/.b", FNM_PATHNAME|FNM_PERIOD, FNM_NOMATCH },
+ { "*?*/*", "a/.b", FNM_PERIOD, 0 },
+ { "*[.]/b", "a./b", FNM_PATHNAME|FNM_PERIOD, 0 },
+ { "*[[:alpha:]]/*[[:alnum:]]", "a/b", FNM_PATHNAME, 0 },
+ /* These three tests should result in error according to SUSv3.
+ * See XCU 2.13.1, XBD 9.3.5, & fnmatch() */
+ { "*[![:digit:]]*/[![:d-d]", "a/b", FNM_PATHNAME, -FNM_NOMATCH },
+ { "*[![:digit:]]*/[[:d-d]", "a/[", FNM_PATHNAME, -FNM_NOMATCH },
+ { "*[![:digit:]]*/[![:d-d]", "a/[", FNM_PATHNAME, -FNM_NOMATCH },
+ { "a?b", "a.b", FNM_PATHNAME|FNM_PERIOD, 0 },
+ { "a*b", "a.b", FNM_PATHNAME|FNM_PERIOD, 0 },
+ { "a[.]b", "a.b", FNM_PATHNAME|FNM_PERIOD, 0 },
+};
+
+int test_fnmatch(void) {
+ int i;
+ unsigned int failed = 0;
+
+ for (i = 0; i < sizeof(tests) / sizeof(*tests); i++) {
+ int r, x;
+
+ r = fnmatch(tests[i].pattern, tests[i].string, tests[i].flags);
+ x = tests[i].expected;
+ if (r != x && (r != FNM_NOMATCH || x != -FNM_NOMATCH)) {
+ failed++;
+ printf("fail - fnmatch(\"%s\", \"%s\", ",
+ tests[i].pattern, tests[i].string);
+ printflags(fnmatch_flags, tests[i].flags);
+ printf(") => %d (expected %d)\n", r, tests[i].expected);
+ }
+ }
+
+ return failed;
+}
diff --git a/fscanf.c b/fscanf.c
new file mode 100644
index 0000000..b03589a
--- /dev/null
+++ b/fscanf.c
@@ -0,0 +1,47 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+
+#define TEST(r, f, x, m) ( \
+((r) = (f)) == (x) || \
+(printf(__FILE__ ":%d: %s failed (" m ")\n", __LINE__, #f, r, x, strerror(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) )
+
+int test_fscanf(void)
+{
+ int i, x, y;
+ int err=0;
+ char a[100], b[100], *s;
+ FILE *f;
+ int p[2];
+
+ TEST(i, pipe(p), 0, "failed to open pipe %d!=%d (%s)");
+ TEST(i, !(f = fdopen(p[0], "rb")), 0, "failed to fdopen pipe %d!=%d (%s)");
+
+ if (!f) {
+ close(p[0]);
+ close(p[1]);
+ return err;
+ }
+
+ TEST(i, write(p[1], "hello, world\n", 13), 13, "write error %d!=%d (%s)");
+ TEST(i, fscanf(f, "%s %[own]", a, b), 2, "got %d fields, expected %d");
+ TEST_S(a, "hello,", "wrong result for %s");
+ TEST_S(b, "wo", "wrong result for %[own]");
+ TEST(i, fgetc(f), 'r', "'%c' != '%c') (%s)");
+
+ TEST(i, write(p[1], " 0x12 0x34", 10), 10, "write error %d!=%d (%s)");
+ TEST(i, fscanf(f, "ld %5i%2i", &x, &y), 1, "got %d fields, expected %d");
+ TEST(i, x, 0x12, "%d != %d");
+ TEST(i, fgetc(f), '3', "'%c' != '%c'");
+
+ fclose(f);
+ close(p[1]);
+
+ return err;
+}
diff --git a/hello.old b/hello.old
new file mode 100644
index 0000000..b6f057b
--- /dev/null
+++ b/hello.old
@@ -0,0 +1,308 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <libgen.h>
+#include <wchar.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <dirent.h>
+#include <fnmatch.h>
+#include <glob.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <grp.h>
+#include <ctype.h>
+#include <time.h>
+#include <regex.h>
+#include <iconv.h>
+#include <ftw.h>
+#include <sys/stat.h>
+#include <limits.h>
+
+extern char **environ;
+
+static char *classes(wchar_t c)
+{
+ int i;
+ static char buf[13];
+ char *p = buf;
+ static const char classname[13][6] = {
+ "alnum", "alpha", "blank", "cntrl",
+ "digit", "graph", "lower", "print",
+ "punct", "space", "upper", "xdigit", ""
+ };
+ static const char flags[] = "nabcdglp!sux";
+ memset(buf, 0, sizeof buf);
+ for (i=0; classname[i][0]; i++)
+ if (iswctype(c, wctype(classname[i])))
+ *p++ = flags[i];
+ else *p++ = '-';
+ return buf;
+}
+
+static int walker(const char *path, const struct stat *st, int type, struct FTW *ftws)
+{
+ char *types[] = { "", "F", "D", "DNR", "NS", "SL", "DP", "SLN" };
+ printf("%d %s: %s: %s\n", ftws->level, path, path+ftws->base, types[type]);
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int c, i, j, k, l;
+ struct passwd *pw;
+ struct group *gr;
+ struct hostent *he;
+ struct addrinfo *aih, *ai, req = { 0 };
+ struct in_addr addr = { inet_addr("127.0.0.1") };
+ glob_t gl;
+ DIR *dir;
+ struct tm tm;
+ time_t mytime;
+ char foo[256], bar[256];
+ regex_t rx;
+ regmatch_t rm;
+ iconv_t cd;
+
+ while ((c = getopt(argc, argv, ":u:g:h:G:F:f:H46Ct:US:r:ei:w:")) >= 0) switch (c) {
+ case 'e':
+ for (i=0; i<128; i++) {
+ printf("%3d: %s\n", i, strerror(i));
+ }
+ break;
+ case 'r':
+ if ((j = regcomp(&rx, optarg, REG_EXTENDED))) {
+ regerror(j, &rx, foo, sizeof foo);
+ printf("regcomp error %d: %s\n", j, foo);
+ break;
+ }
+ for (;;) {
+ fgets(foo, sizeof foo, stdin);
+ if (feof(stdin)) break;
+ l = strlen(foo);
+ if (foo[l-1] == '\n') foo[l-1] = 0;
+ k = regexec(&rx, foo, 1, &rm, 0);
+ switch (k) {
+ case 0:
+ printf("matched %.*s\n", (int)(rm.rm_eo-rm.rm_so), foo+rm.rm_so);
+ break;
+ default:
+ regerror(k, &rx, foo, sizeof foo);
+ printf("%s\n", foo);
+ break;
+ }
+ }
+ regfree(&rx);
+ break;
+ case 'i':
+ cd = iconv_open("UTF-8", optarg);
+ printf("iconv_open returned %lx\n", (long)cd);
+ if (cd != (iconv_t)-1) for (;;) {
+ char *s=foo, *t=bar;
+ size_t l, k = sizeof bar;
+ fgets(foo, sizeof foo, stdin);
+ if (feof(stdin)) break;
+ l = strlen(foo);
+ if (foo[l-1] == '\n') foo[l-1] = 0;
+ errno = 0;
+ printf("iconv returned %zu\n", iconv(cd, &s, &l, &t, &k));
+ *t = 0;
+ printf("errno=%d (%s), inb=%zu, outb=%zu\nresult=[%s]\n", errno, strerror(errno), l, k, bar);
+ }
+ break;
+ case 'S':
+ printf("sscanf returned %d\n", sscanf(optarg, "%3i%i %i%[abcdefg] %d", &i, &j, &k, foo, &c));
+ printf("input=[%s] i=%d j=%d k=%d foo=[%s] c=%d\n", optarg, i, j, k, foo, c);
+ break;
+ case 'U':
+ for (;1;) {
+ wchar_t wc;
+ fgets(foo, sizeof foo, stdin);
+ if (feof(stdin)) break;
+ for (i=j=0; foo[i] && foo[i] != '\n'; i++) {
+ if (1 && (l = mbtowc(&wc, foo+i, 4)) < 0) { bar[j++] = '?'; continue; }
+ if (0 && (l = mbrtowc(&wc, foo+i, 1, NULL)) < 0) {
+ if (l == -2) continue;
+ bar[j++] = '?';
+ mbrtowc(NULL, NULL, 0, NULL);
+ if ((l = mbrtowc(&wc, foo+i, 1, NULL)) == -1) {
+ mbrtowc(NULL, NULL, 0, NULL);
+ continue;
+ } else if (l == -2) continue;
+ }
+ if (wc > 126 || wc < 32) bar[j++] = '.';
+ else bar[j++] = wc;
+ i += l-1;
+ }
+ bar[j++] = 0;
+ foo[i++] = 0;
+ puts(bar);
+ }
+ if (1) {
+ unsigned char mbs[4] = { 0, 0, 0, 0 };
+ int l;
+ wchar_t c;
+
+ for (mbs[0]=0x00; mbs[0]<0xf5; mbs[0]++)
+ for (mbs[1]=0x80; mbs[1]<(mbs[0]<0xc0?0x81:0xc0); mbs[1]++)
+ for (mbs[2]=0x80; mbs[2]<(mbs[0]<0xe0?0x81:0xc0); mbs[2]++)
+ for (mbs[3]=0x80; mbs[3]<(mbs[0]<0xf0?0x81:0xc0); mbs[3]++) {
+ l = mbtowc(&c, mbs, 4);
+ //l = mbrtowc(&c, mbs, 4, NULL);
+ //mbrtowc(NULL, NULL, 0, NULL);
+ if (l < 0) c = 0;
+ printf("%02x %02x %02x %02x [%2d %06x %2d %s] %lc\n", mbs[0], mbs[1], mbs[2], mbs[3], l, c, wcwidth(c), classes(c), iscntrl(c) || c<0 ? L' ' : c);
+ }
+ //l = wcrtomb(mbs, i, NULL);
+ //printf("char %06x: %02x %02x %02x %02x [%d]\n", i, mbs[0], mbs[1], mbs[2], mbs[3], l);
+ }
+ for (i=0; i<0; i++) {
+ unsigned char mbs[7] = { 0, 0, 0, 0, 0, 0, 0 };
+ int l;
+ wchar_t c;
+ l = wcrtomb(mbs, i, NULL);
+ //printf("char %06x: %02x %02x %02x %02x [%d]\n", i, mbs[0], mbs[1], mbs[2], mbs[3], l);
+ l = mbrtowc(&c, mbs, 4, NULL);
+ printf("char %06x: %02x %02x %02x %02x [%d %06x]\n", i, mbs[0], mbs[1], mbs[2], mbs[3], l, c);
+ }
+ break;
+ case 't':
+ mytime = atoll(optarg);
+ for (i=0; i<6; i++) {
+ time_t time2 = mytime + 1800*i;
+ tm = *localtime(&time2);
+ strftime(foo, sizeof foo, "%c", &tm);
+ printf("%s [yd=%d dst=%d]\n", foo, tm.tm_yday, tm.tm_isdst);
+ }
+ break;
+ case 'H':
+ printf("hello, world!\n");
+ break;
+ case 'C':
+ req.ai_flags ^= AI_CANONNAME;
+ break;
+ case '4':
+ req.ai_family = AF_INET;
+ break;
+ case '6':
+ req.ai_family = AF_INET6;
+ break;
+ case 'u':
+ if ((pw = getpwnam(optarg)) || (isdigit(optarg[0]) && (pw = getpwuid(atoi(optarg))))) {
+ printf("pw_name = %s\n", pw->pw_name);
+ printf("pw_passwd = %s\n", pw->pw_passwd);
+ printf("pw_uid = %d\n", pw->pw_uid);
+ printf("pw_gid = %d\n", pw->pw_gid);
+ printf("pw_gecos = %s\n", pw->pw_gecos);
+ printf("pw_dir = %s\n", pw->pw_dir);
+ printf("pw_shell = %s\n", pw->pw_shell);
+ }
+ break;
+ case 'g':
+ if ((gr = getgrnam(optarg)) || (isdigit(optarg[0]) && (gr = getgrgid(atoi(optarg))))) {
+ printf("gr_name = %s\n", gr->gr_name);
+ printf("gr_passwd = %s\n", gr->gr_passwd);
+ printf("gr_gid = %d\n", gr->gr_gid);
+ for (i=0; gr->gr_mem[i]; i++)
+ printf("gr_mem[%d] = %s\n", i, gr->gr_mem[i]);
+ }
+ break;
+ case 'h':
+ l = getaddrinfo(optarg, NULL, &req, &aih);
+ printf("getaddrinfo returned %d\n", l);
+ if (!l) {
+ char tmp[100];
+ printf("aih: %p\n", aih);
+ if (aih->ai_canonname)
+ printf("canonical name: %s\n", aih->ai_canonname);
+ for (ai=aih; ai; ai=ai->ai_next) {
+ if (!getnameinfo(ai->ai_addr, ai->ai_addrlen, tmp, sizeof tmp, NULL, 0, NI_NUMERICHOST))
+ printf("address = %s\n", tmp);
+ else
+ printf("address = %08x\n", ntohl(((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr));
+ }
+ if (!getnameinfo(aih->ai_addr, aih->ai_addrlen, tmp, sizeof tmp, NULL, 0, 0)) {
+ printf("getnameinfo: %s\n", tmp);
+ }
+ freeaddrinfo(aih);
+ }
+ if ((he = gethostbyname(optarg))) {
+ char addr[4];
+ printf("gethostbyname reports:\n");
+ for (j=0; he->h_addr_list[j]; j++)
+ printf("%d.%d.%d.%d\n", (unsigned char)he->h_addr_list[j][0], (unsigned char)he->h_addr_list[j][1], (unsigned char)he->h_addr_list[j][2], (unsigned char)he->h_addr_list[j][3]);
+ for (j=0; he->h_aliases[j]; j++)
+ printf("alias %s\n", he->h_aliases[j]);
+ printf("name %s\n", he->h_name);
+ memcpy(addr, he->h_addr_list[0], 4);
+#if 1
+ if ((he = gethostbyaddr(addr, 4, AF_INET))) {
+ printf("gethostbyaddr reports:\n");
+ for (j=0; he->h_addr_list[j]; j++)
+ printf("%d.%d.%d.%d\n", (unsigned char)he->h_addr_list[j][0], (unsigned char)he->h_addr_list[j][1], (unsigned char)he->h_addr_list[j][2], (unsigned char)he->h_addr_list[j][3]);
+ for (j=0; he->h_aliases && he->h_aliases[j]; j++)
+ printf("alias %s\n", he->h_aliases[j]);
+ printf("name %s\n", he->h_name);
+ }
+#endif
+ }
+ break;
+ case 'G':
+ printf("matching %s\n", optarg);
+ glob(optarg, GLOB_MARK, NULL, &gl);
+ for (j=0; j<gl.gl_pathc; j++)
+ printf(" [%d] [%s]\n", j, gl.gl_pathv[j]);
+ globfree(&gl);
+ break;
+ case 'F':
+ pw = getpwuid(getuid());
+ if (pw && (dir = opendir(pw->pw_dir))) {
+ struct dirent *de;
+ while ((de = readdir(dir)))
+ if (!fnmatch(optarg, de->d_name, 0))
+ printf("%s\n", de->d_name);
+ closedir(dir);
+ }
+ break;
+ case 'f':
+ printf("%s -> [%s]\n", optarg, inet_ntoa(addr));
+ if (addr.s_addr != (unsigned int)-1) {
+ char foo[100];
+ struct sockaddr_in sin = { AF_INET, htons(79), addr };
+ int sock = socket(PF_INET, SOCK_STREAM, 0);
+ connect(sock, (void *)&sin, sizeof sin);
+ write(sock, optarg, strlen(optarg));
+ write(sock, "\n", 1);
+ while ((l = read(sock, foo, sizeof foo)) > 0)
+ fwrite(foo, 1, l, stdout);
+ fflush(stdout);
+ close(sock);
+ }
+ break;
+ case 'w':
+ printf("nftw returned %d\n", nftw(optarg, walker, 1024, 0));
+ printf("errno=%d (%s)\n", errno, strerror(errno));
+ break;
+ case ':':
+ for (;;) {
+ char foo[100], opt[3] = { '-', optopt, 0 };
+ char *newargs[] = { argv[0], opt, foo, NULL };
+ fgets(foo, sizeof foo, stdin);
+ if (feof(stdin)) return 0;
+ i = strlen(foo);
+ if (!i) return 0;
+ if (foo[i-1] == '\n') foo[i-1] = 0;
+ optind = 1;
+ main(3, newargs);
+ }
+ break;
+ case '?':
+ printf("unknown option %lc\n", optopt);
+ return -1;
+ }
+ return 0;
+}
diff --git a/mbc.c b/mbc.c
new file mode 100644
index 0000000..1125fff
--- /dev/null
+++ b/mbc.c
@@ -0,0 +1,92 @@
+#include <stdio.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <langinfo.h>
+
+/* r = place to store result
+ * f = function call to test (or any expression)
+ * x = expected result
+ * m = message to print on failure (with formats for r & x)
+**/
+
+#define TEST(r, f, x, m) ( \
+memset(&st, 0, sizeof st), \
+((r) = (f)) == (x) || \
+(printf(__FILE__ ":%d: %s failed (" m ")\n", __LINE__, #f, r, x), err++, 0) )
+
+#define TEST_S(s, x, m) ( \
+!strcmp((s),(x)) || \
+(printf(__FILE__ ":%d: [%s] != [%s] (%s)\n", __LINE__, s, x, m), err++, 0) )
+
+int test_mbc(void)
+{
+ char b[32];
+ char *s;
+ const char *cs;
+ int i;
+ int err=0;
+ mbstate_t st, st2;
+ wchar_t wc, wcs[32];
+
+ setlocale(LC_CTYPE, "en_US.UTF-8") ||
+ setlocale(LC_CTYPE, "en_GB.UTF-8") ||
+ setlocale(LC_CTYPE, "en.UTF-8") ||
+ setlocale(LC_CTYPE, "POSIX.UTF-8") ||
+ setlocale(LC_CTYPE, "C.UTF-8") ||
+ setlocale(LC_CTYPE, "UTF-8") ||
+ setlocale(LC_CTYPE, "");
+
+ TEST(i, mbsrtowcs(wcs, (cs="abcdef",&cs), 3, &st), 3, "wrong semantics for wcs buf len, %d != %d");
+ TEST(i, mbsrtowcs(wcs, (cs="abcdef",&cs), 8, &st), 6, "wrong semantics for wcs buf len, %d != %d");
+ TEST(i, mbsrtowcs(NULL, (cs="abcdef",&cs), 2, &st), 6, "wrong semantics for NULL wcs, %d != %d");
+
+ if (strcmp(nl_langinfo(CODESET), "UTF-8")) {
+ printf(__FILE__ ": cannot set UTF-8 locale for test"
+ " (codeset=%s)\n", nl_langinfo(CODESET));
+ return 0;
+ }
+
+ TEST(i, mbrtowc(&wc, "\x80", 1, &st), -1, "failed to catch error %d != %d");
+ TEST(i, mbrtowc(&wc, "\xc0", 1, &st), -1, "failed to catch illegal initial, %d != %d");
+
+ TEST(i, mbrtowc(&wc, "\xc0\x80", 2, &st), -1, "aliasing nul %d != %d");
+ TEST(i, mbrtowc(&wc, "\xc0\xaf", 2, &st), -1, "aliasing slash %d != %d");
+ TEST(i, mbrtowc(&wc, "\xe0\x80\xaf", 3, &st), -1, "aliasing slash %d != %d");
+ TEST(i, mbrtowc(&wc, "\xf0\x80\x80\xaf", 4, &st), -1, "aliasing slash %d != %d");
+ TEST(i, mbrtowc(&wc, "\xf8\x80\x80\x80\xaf", 5, &st), -1, "aliasing slash %d != %d");
+ TEST(i, mbrtowc(&wc, "\xfc\x80\x80\x80\x80\xaf", 6, &st), -1, "aliasing slash %d != %d");
+ TEST(i, mbrtowc(&wc, "\xe0\x82\x80", 3, &st), -1, "aliasing U+0080 %d != %d");
+ TEST(i, mbrtowc(&wc, "\xe0\x9f\xbf", 3, &st), -1, "aliasing U+07FF %d != %d");
+ TEST(i, mbrtowc(&wc, "\xf0\x80\xa0\x80", 4, &st), -1, "aliasing U+0800 %d != %d");
+ TEST(i, mbrtowc(&wc, "\xf0\x8f\xbf\xbd", 4, &st), -1, "aliasing U+FFFD %d != %d");
+
+ TEST(i, mbrtowc(&wc, "\xed\xa0\x80", 3, &st), -1, "failed to catch surrogate, %d != %d");
+ TEST(i, mbrtowc(&wc, "\xef\xbf\xbe", 3, &st), 3, "failed to accept U+FFFE, %d != %d");
+ TEST(i, mbrtowc(&wc, "\xef\xbf\xbf", 3, &st), 3, "failed to accept U+FFFF, %d != %d");
+ TEST(i, mbrtowc(&wc, "\xf4\x8f\xbf\xbe", 4, &st), 4, "failed to accept U+10FFFE, %d != %d");
+ TEST(i, mbrtowc(&wc, "\xf4\x8f\xbf\xbf", 4, &st), 4, "failed to accept U+10FFFF, %d != %d");
+
+ TEST(i, mbrtowc(&wc, "\xc2\x80", 2, &st), 2, "wrong length %d != %d");
+ TEST(i, (mbrtowc(&wc, "\xc2\x80", 2, &st),wc), 0x80, "wrong char %04x != %04x");
+ TEST(i, mbrtowc(&wc, "\xe0\xa0\x80", 3, &st), 3, "wrong length %d != %d");
+ TEST(i, (mbrtowc(&wc, "\xe0\xa0\x80", 3, &st),wc), 0x800, "wrong char %04x != %04x");
+ TEST(i, mbrtowc(&wc, "\xf0\x90\x80\x80", 4, &st), 4, "wrong length %d != %d");
+ TEST(i, (mbrtowc(&wc, "\xf0\x90\x80\x80", 4, &st),wc), 0x10000, "wrong char %04x != %04x");
+
+ memset(&st2, 0, sizeof st2);
+ TEST(i, mbrtowc(&wc, "\xc2", 1, &st2), -2, "failed to accept initial byte, %d != %d");
+ TEST(i, mbrtowc(&wc, "\x80", 1, &st2), 1, "failed to resume, %d != %d");
+ TEST(i, wc, 0x80, "wrong char %04x != %04x");
+
+ memset(&st2, 0, sizeof st2);
+ TEST(i, mbrtowc(&wc, "\xc2", 1, &st2), -2, "failed to accept initial byte, %d != %d");
+ TEST(i, mbsrtowcs(wcs, (cs="\xa0""abc",&cs), 32, &st2), 4, "failed to resume, %d != %d");
+ TEST(i, wcs[0], 0xa0, "wrong char %04x != %04x");
+ TEST(i, wcs[1], 'a', "wrong char %04x != %04x");
+ TEST(i, !cs, 1, "wrong final position %d != %d");
+
+ return err;
+}
+
diff --git a/popen.c b/popen.c
new file mode 100644
index 0000000..8a5843a
--- /dev/null
+++ b/popen.c
@@ -0,0 +1,51 @@
+#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 test_popen(void)
+{
+ int i;
+ char foo[6];
+ char cmd[64];
+ int err = 0;
+ FILE *f;
+
+ TEST_E(f = popen("echo hello", "r"));
+ if (f) {
+ 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"));
+ if (f) {
+ TEST_E(fputs("hello", f) >= 0);
+ TEST(i, pclose(f), 0, "exit status %04x != %04x");
+ TEST(i, got_sig, 1, "child process did not send signal");
+ }
+ signal(SIGUSR1, SIG_DFL);
+
+ return err;
+}
diff --git a/pthread.c b/pthread.c
new file mode 100644
index 0000000..14fbc4a
--- /dev/null
+++ b/pthread.c
@@ -0,0 +1,161 @@
+#include <pthread.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.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_S(s, x, m) ( \
+!strcmp((s),(x)) || \
+(printf(__FILE__ ":%d: [%s] != [%s] (%s)\n", __LINE__, s, x, m), err++, 0) )
+
+static pthread_key_t k1, k2;
+
+static void dtor(void *p)
+{
+ *(int *)p = 1;
+}
+
+static void *start1(void *arg)
+{
+ return arg;
+}
+
+static void *start2(void *arg)
+{
+ int *p = arg;
+ if (pthread_setspecific(k1, p) || pthread_setspecific(k2, p+1))
+ return arg;
+ return 0;
+}
+
+static void *start3(void *arg)
+{
+ pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0);
+ pthread_barrier_wait(arg);
+ for (;;);
+ return 0;
+}
+
+static void cleanup4(void *arg)
+{
+ *(int *)arg = 1;
+}
+
+static void *start4(void *arg)
+{
+ pthread_cleanup_push(cleanup4, arg);
+ sleep(3);
+ pthread_cleanup_pop(0);
+ return 0;
+}
+
+static void *start5(void *arg)
+{
+ pthread_mutex_lock(arg);
+ return 0;
+}
+
+static void *start6(void *arg)
+{
+ void **args = arg;
+ pthread_mutex_lock(args[1]);
+ pthread_barrier_wait(args[0]);
+ nanosleep(&(struct timespec){ .tv_nsec = 10000000 }, 0);
+ return 0;
+}
+
+
+int test_pthread(void)
+{
+ pthread_t td;
+ int err = 0;
+ int r;
+ void *res;
+ int foo[2], bar[2];
+ pthread_barrier_t barrier2;
+ pthread_mutexattr_t mtx_a;
+ pthread_mutex_t mtx, *sh_mtx;
+ int fd;
+
+ TEST(r, pthread_barrier_init(&barrier2, 0, 2), 0, "creating barrier");
+
+ /* Test basic thread creation and joining */
+ TEST(r, pthread_create(&td, 0, start1, &res), 0, "failed to create thread");
+ res = 0;
+ TEST(r, pthread_join(td, &res), 0, "failed to join");
+ TEST(r, (res==&res), 1, "wrong result from join");
+
+ /* Test POSIX thread-specific data */
+ TEST(r, pthread_key_create(&k1, dtor), 0, "failed to create key");
+ TEST(r, pthread_key_create(&k2, dtor), 0, "failed to create key");
+ foo[0] = foo[1] = 0;
+ TEST(r, pthread_setspecific(k1, bar), 0, "failed to set tsd");
+ TEST(r, pthread_setspecific(k2, bar+1), 0, "failed to set tsd");
+ TEST(r, pthread_create(&td, 0, start2, foo), 0, "failed to create thread");
+ TEST(r, pthread_join(td, &res), 0, "failed to join");
+ TEST(res, res, 0, "pthread_setspecific failed in thread");
+ TEST(r, foo[0], 1, "dtor failed to run");
+ TEST(r, foo[1], 1, "dtor failed to run");
+ TEST(res, pthread_getspecific(k1), bar, "tsd corrupted");
+ TEST(res, pthread_getspecific(k2), bar+1, "tsd corrupted");
+ TEST(r, pthread_setspecific(k1, 0), 0, "failed to clear tsd");
+ TEST(r, pthread_setspecific(k2, 0), 0, "failed to clear tsd");
+ TEST(r, pthread_key_delete(k1), 0, "failed to destroy key");
+ TEST(r, pthread_key_delete(k2), 0, "failed to destroy key");
+
+ /* Asynchronous cancellation */
+ TEST(r, pthread_create(&td, 0, start3, &barrier2), 0, "failed to create thread");
+ pthread_barrier_wait(&barrier2);
+ TEST(r, pthread_cancel(td), 0, "cancelling");
+ TEST(r, pthread_join(td, &res), 0, "joining cancelled thread");
+ TEST(res, res, PTHREAD_CANCELLED, "cancelled thread exit status");
+
+ /* Cancellation cleanup handlers */
+ foo[0] = 0;
+ TEST(r, pthread_create(&td, 0, start4, foo), 0, "failed to create thread");
+ TEST(r, pthread_cancel(td), 0, "cancelling");
+ TEST(r, pthread_join(td, &res), 0, "joining cancelled thread");
+ TEST(res, res, PTHREAD_CANCELLED, "cancelled thread exit status");
+ TEST(r, foo[0], 1, "cleanup handler failed to run");
+
+ /* Robust mutexes */
+ TEST(r, pthread_mutexattr_init(&mtx_a), 0, "initializing mutex attr");
+ TEST(r, pthread_mutexattr_setrobust(&mtx_a, PTHREAD_MUTEX_ROBUST), 0, "setting robust attribute");
+ TEST(r, pthread_mutex_init(&mtx, &mtx_a), 0, "initializing robust mutex");
+ TEST(r, pthread_mutex_lock(&mtx), 0, "locking robust mutex");
+ TEST(r, pthread_mutex_unlock(&mtx), 0, "unlocking robust mutex");
+ TEST(r, pthread_create(&td, 0, start5, &mtx), 0, "failed to create thread");
+ TEST(r, pthread_join(td, &res), 0, "joining thread");
+ TEST(r, pthread_mutex_lock(&mtx), EOWNERDEAD, "locking orphaned robust mutex %d!=%d");
+ TEST(r, pthread_mutex_unlock(&mtx), 0, "unlocking orphaned robust mutex %d!=%d");
+ TEST(r, pthread_mutex_lock(&mtx), ENOTRECOVERABLE, "re-locking orphaned robust mutex %d!=%d");
+ TEST(r, pthread_mutex_destroy(&mtx), 0, "destroying unrecoverable mutex %d!=%d");
+
+ TEST(r, pthread_mutex_init(&mtx, &mtx_a), 0, "initializing robust mutex");
+ TEST(r, pthread_create(&td, 0, start5, &mtx), 0, "failed to create thread");
+ TEST(r, pthread_join(td, &res), 0, "joining thread");
+ TEST(r, pthread_mutex_lock(&mtx), EOWNERDEAD, "locking orphaned robust mutex %d!=%d");
+ TEST(r, pthread_mutex_consistent(&mtx), 0, "%d!=%d");
+ TEST(r, pthread_mutex_unlock(&mtx), 0, "unlocking orphaned robust mutex %d!=%d");
+ TEST(r, pthread_mutex_lock(&mtx), 0, "re-locking orphaned robust mutex %d!=%d");
+ TEST(r, pthread_mutex_destroy(&mtx), 0, "destroying mutex %d!=%d");
+
+ TEST(r, pthread_mutex_init(&mtx, &mtx_a), 0, "%d != %d");
+ TEST(r, pthread_create(&td, 0, start6, (void *[]){ &barrier2, &mtx }), 0, "%d != %d");
+ pthread_barrier_wait(&barrier2);
+ TEST(r, pthread_mutex_lock(&mtx), EOWNERDEAD, "%d != %d");
+ TEST(r, pthread_join(td, &res), 0, "%d != %d");
+ TEST(r, pthread_mutex_consistent(&mtx), 0, "%d != %d");
+ TEST(r, pthread_mutex_unlock(&mtx), 0, "%d != %d");
+ TEST(r, pthread_mutex_destroy(&mtx), 0, "%d != %d");
+
+ //TEST(r, (fd=open("/dev/zero", O_RDWR))>=0, 1, "opening zero page file");
+ //TEST(r,
+
+ return err;
+}
diff --git a/qsort.c b/qsort.c
new file mode 100644
index 0000000..818426c
--- /dev/null
+++ b/qsort.c
@@ -0,0 +1,59 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+static int scmp(const void *a, const void *b)
+{
+ return strcmp(*(char **)a, *(char **)b);
+}
+
+static int icmp(const void *a, const void *b)
+{
+ return *(int*)a - *(int*)b;
+}
+
+#define FAIL(m) (printf(__FILE__ ":%d: %s failed\n", __LINE__, m), err++, 0)
+
+int test_qsort(void)
+{
+ int i;
+ int err=0;
+ /* 26 items -- even */
+ char *s[] = {
+ "Bob", "Alice", "John", "Ceres",
+ "Helga", "Drepper", "Emeralda", "Zoran",
+ "Momo", "Frank", "Pema", "Xavier",
+ "Yeva", "Gedun", "Irina", "Nono",
+ "Wiener", "Vincent", "Tsering", "Karnica",
+ "Lulu", "Quincy", "Osama", "Riley",
+ "Ursula", "Sam"
+ };
+ /* 23 items -- odd, prime */
+ int n[] = {
+ 879045, 394, 99405644, 33434, 232323, 4334, 5454,
+ 343, 45545, 454, 324, 22, 34344, 233, 45345, 343,
+ 848405, 3434, 3434344, 3535, 93994, 2230404, 4334
+ };
+
+ qsort(s, sizeof(s)/sizeof(char *), sizeof(char *), scmp);
+ for (i=0; i<sizeof(s)/sizeof(char *)-1; i++) {
+ if (strcmp(s[i], s[i+1]) > 0) {
+ FAIL("string sort");
+ for (i=0; i<sizeof(s)/sizeof(char *); i++)
+ printf("\t%s\n", s[i]);
+ break;
+ }
+ }
+
+ qsort(n, sizeof(n)/sizeof(int), sizeof(int), icmp);
+ for (i=0; i<sizeof(n)/sizeof(int)-1; i++) {
+ if (n[i] > n[i+1]) {
+ FAIL("integer sort");
+ for (i=0; i<sizeof(n)/sizeof(int); i++)
+ printf("\t%d\n", n[i]);
+ break;
+ }
+ }
+
+ return err;
+}
diff --git a/sem.c b/sem.c
new file mode 100644
index 0000000..4930e4d
--- /dev/null
+++ b/sem.c
@@ -0,0 +1,52 @@
+#include <pthread.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <semaphore.h>
+#include <time.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_S(s, x, m) ( \
+!strcmp((s),(x)) || \
+(printf(__FILE__ ":%d: [%s] != [%s] (%s)\n", __LINE__, s, x, m), err++, 0) )
+
+int test_sem(void)
+{
+ int err = 0;
+ int r;
+ void *res;
+ char buf[100];
+ struct timespec ts;
+ sem_t *sem, *sem2;
+ int val;
+
+ clock_gettime(CLOCK_REALTIME, &ts);
+ snprintf(buf, sizeof buf, "/testsuite-%d-%d", (int)getpid(), (int)ts.tv_nsec);
+
+ TEST(r, !(sem=sem_open(buf, O_CREAT|O_EXCL, 0700, 1)), 0, "could not open sem");
+
+ TEST(r, sem_getvalue(sem, &val), 0, "failed to get sem value");
+ TEST(r, val, 1, "wrong initial semaphore value");
+
+ TEST(r, !(sem2=sem_open(buf, 0)), 0, "could not reopen sem");
+ TEST(r, sem!=sem2, 0, "reopened sem has different address");
+
+ TEST(r, sem_wait(sem), 0, "failed on sem wait");
+ TEST(r, sem_getvalue(sem2, &val), 0, "failed to get sem value");
+ TEST(r, val, 0, "wrong semaphore value on second handle");
+
+ TEST(r, sem_post(sem), 0, "failed on sem post");
+ TEST(r, sem_getvalue(sem2, &val), 0, "failed to get sem value");
+ TEST(r, val, 1, "wrong semaphore value on second handle");
+
+ TEST(r, sem_close(sem), 0, "failed to close sem");
+ TEST(r, sem_close(sem), 0, "failed to close sem second time");
+ TEST(r, sem_unlink(buf), 0, "failed to unlink sem");
+
+ return err;
+}
diff --git a/snprintf.c b/snprintf.c
new file mode 100644
index 0000000..1e563e5
--- /dev/null
+++ b/snprintf.c
@@ -0,0 +1,120 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <math.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_S(s, x, m) ( \
+!strcmp((s),(x)) || \
+(printf(__FILE__ ":%d: [%s] != [%s] (%s)\n", __LINE__, s, x, m), err++, 0) )
+
+static const struct {
+ const char *fmt;
+ int i;
+ const char *expect;
+} int_tests[] = {
+ /* width, precision, alignment */
+ { "%04d", 12, "0012" },
+ { "%.3d", 12, "012" },
+ { "%3d", 12, " 12" },
+ { "%-3d", 12, "12 " },
+ { "%+3d", 12, "+12" },
+ { "%+-5d", 12, "+12 " },
+ { "%+- 5d", 12, "+12 " },
+ { "%- 5d", 12, " 12 " },
+ { "% d", 12, " 12" },
+ { "%0-5d", 12, "12 " },
+ { "%-05d", 12, "12 " },
+
+ /* ...explicit precision of 0 shall be no characters. */
+ { "%.0d", 0, "" },
+ { "%.0o", 0, "" },
+ { "%#.0d", 0, "" },
+ { "%#.0o", 0, "" },
+ { "%#.0x", 0, "" },
+
+ /* hex: test alt form and case */
+ { "%x", 63, "3f" },
+ { "%#x", 63, "0x3f" },
+ { "%X", 63, "3F" },
+
+ /* octal: test alt form */
+ { "%o", 15, "17" },
+ { "%#o", 15, "017" },
+
+ { NULL, 0.0, NULL }
+};
+
+static const struct {
+ const char *fmt;
+ double f;
+ const char *expect;
+} fp_tests[] = {
+ /* basic form, handling of exponent/precision for 0 */
+ { "%e", 0.0, "0.000000e+00" },
+ { "%f", 0.0, "0.000000" },
+ { "%g", 0.0, "0" },
+ { "%#g", 0.0, "0.00000" },
+
+ /* rounding */
+ { "%f", 1.1, "1.100000" },
+ { "%f", 1.2, "1.200000" },
+ { "%f", 1.3, "1.300000" },
+ { "%f", 1.4, "1.400000" },
+ { "%f", 1.5, "1.500000" },
+
+ /* correctness in DBL_DIG places */
+ { "%.15g", 1.23456789012345, "1.23456789012345" },
+
+ /* correct choice of notation for %g */
+ { "%g", 0.0001, "0.0001" },
+ { "%g", 0.00001, "1e-05" },
+ { "%g", 123456, "123456" },
+ { "%g", 1234567, "1.23457e+06" },
+ { "%.7g", 1234567, "1234567" },
+ { "%.7g", 12345678, "1.234568e+07" },
+
+ /* pi in double precision, printed to a few extra places */
+ { "%.15f", M_PI, "3.141592653589793" },
+ { "%.18f", M_PI, "3.141592653589793116" },
+
+ /* exact conversion of large integers */
+ { "%.0f", 340282366920938463463374607431768211456.0,
+ "340282366920938463463374607431768211456" },
+
+ { NULL, 0.0, NULL }
+};
+
+int test_snprintf(void)
+{
+ int i, j;
+ int err=0;
+ char b[500], *s;
+
+ strcpy(b, "xxxxxxxx");
+ TEST(i, snprintf(b, 4, "%d", 123456), 6, "length returned %d != %d");
+ TEST_S(b, "123", "incorrect output");
+ TEST(i, b[5], 'x', "buffer overrun");
+
+#ifndef DISABLE_SLOW_TESTS
+ errno = 0;
+ TEST(i, snprintf(NULL, 0, "%.*u", 2147483647, 0), 2147483647, "cannot print max length %d");
+ TEST(i, snprintf(NULL, 0, "%.*u ", 2147483647, 0), -1, "integer overflow %d");
+ TEST(i, errno, EOVERFLOW, "after overflow: %d != %d");
+#endif
+ for (j=0; int_tests[j].fmt; j++) {
+ TEST(i, snprintf(b, sizeof b, int_tests[j].fmt, int_tests[j].i), strlen(b), "%d != %d");
+ TEST_S(b, int_tests[j].expect, "bad integer conversion");
+ }
+
+ for (j=0; fp_tests[j].fmt; j++) {
+ TEST(i, snprintf(b, sizeof b, fp_tests[j].fmt, fp_tests[j].f), strlen(b), "%d != %d");
+ TEST_S(b, fp_tests[j].expect, "bad floating point conversion");
+ }
+
+ return err;
+}
diff --git a/sscanf.c b/sscanf.c
new file mode 100644
index 0000000..a692b50
--- /dev/null
+++ b/sscanf.c
@@ -0,0 +1,90 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.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_S(s, x, m) ( \
+!strcmp((s),(x)) || \
+(printf(__FILE__ ":%d: [%s] != [%s] (%s)\n", __LINE__, s, x, m), err++, 0) )
+
+#define TEST_F(x) ( \
+TEST(i, sscanf(# x, "%lf", &d), 1, "got %d fields, expected %d"), \
+TEST(t, d, (double)x, "%g != %g") )
+
+int test_sscanf(void)
+{
+ int i;
+ int err=0;
+ char a[100], b[100], *s;
+ int x, y, z, u, v;
+ double d, t;
+ long lo[10];
+
+ TEST(i, sscanf("hello, world\n", "%s %s", a, b), 2, "only %d fields, expected %d");
+ TEST_S(a, "hello,", "");
+ TEST_S(b, "world", "");
+
+ TEST(i, sscanf("hello, world\n", "%[hel]%s", a, b), 2, "only %d fields, expected %d");
+ TEST_S(a, "hell", "");
+ TEST_S(b, "o,", "");
+
+ TEST(i, sscanf("hello, world\n", "%[hel] %s", a, b), 2, "only %d fields, expected %d");
+ TEST_S(a, "hell", "");
+ TEST_S(b, "o,", "");
+
+ a[8] = 'X';
+ a[9] = 0;
+ TEST(i, sscanf("hello, world\n", "%8c%8c", a, b), 1, "%d fields, expected %d");
+ TEST_S(a, "hello, wX", "");
+
+ TEST(i, sscanf("56789 0123 56a72", "%2d%d%*d %[0123456789]\n", &x, &y, a), 3, "only %d fields, expected %d");
+ TEST(i, x, 56, "%d != %d");
+ TEST(i, y, 789, "%d != %d");
+ TEST_S(a, "56", "");
+
+ TEST(i, sscanf("011 0x100 11 0x100 100", "%i %i %o %x %x\n", &x, &y, &z, &u, &v), 5, "only %d fields, expected %d");
+ TEST(i, x, 9, "%d != %d");
+ TEST(i, y, 256, "%d != %d");
+ TEST(i, z, 9, "%d != %d");
+ TEST(i, u, 256, "%d != %d");
+ TEST(i, v, 256, "%d != %d");
+
+ TEST(i, sscanf("20 xyz", "%d %d\n", &x, &y), 1, "only %d fields, expected %d");
+ TEST(i, x, 20, "%d != %d");
+
+ TEST(i, sscanf("xyz", "%d\n", &x, &y), 0, "got %d fields, expected no match (%d)");
+
+ TEST(i, sscanf("", "%d\n", &x, &y), -1, "got %d fields, expected input failure (%d)");
+
+ TEST(i, sscanf(" 12345 6", "%2d%d%d", &x, &y, &z), 3, "only %d fields, expected %d");
+ TEST(i, x, 12, "%d != %d");
+ TEST(i, y, 345, "%d != %d");
+ TEST(i, z, 6, "%d != %d");
+
+ TEST(i, sscanf(" 0x12 0x34", "%5i%2i", &x, &y), 1, "got %d fields, expected %d");
+ TEST(i, x, 0x12, "%d != %d");
+
+ TEST_F(123);
+ TEST_F(123.0);
+ TEST_F(123.0e+0);
+ TEST_F(123.0e+4);
+ TEST_F(1.234e1234);
+ TEST_F(1.234e-1234);
+ TEST_F(1.234e56789);
+ TEST_F(1.234e-56789);
+ TEST_F(-0.5);
+ TEST_F(0.1);
+ TEST_F(0.2);
+ TEST_F(0.1e-10);
+ TEST_F(0x1234p56);
+
+ TEST(i, sscanf("10e", "%lf", &d), 0, "got %d fields, expected no match (%d)");
+ TEST(i, sscanf("", "%lf\n", &d), -1, "got %d fields, expected input failure (%d)");
+
+
+ return err;
+}
diff --git a/string.c b/string.c
new file mode 100644
index 0000000..2a090de
--- /dev/null
+++ b/string.c
@@ -0,0 +1,118 @@
+#define _BSD_SOURCE
+#include <stdio.h>
+#include <string.h>
+
+/* r = place to store result
+ * f = function call to test (or any expression)
+ * x = expected result
+ * m = message to print on failure (with formats for r & x)
+**/
+
+#define TEST(r, f, x, m) ( \
+((r) = (f)) == (x) || \
+(printf(__FILE__ ":%d: %s failed (" m ")\n", __LINE__, #f, r, x), err++, 0) )
+
+#define TEST_S(s, x, m) ( \
+!strcmp((s),(x)) || \
+(printf(__FILE__ ":%d: [%s] != [%s] (%s)\n", __LINE__, s, x, m), err++, 0) )
+
+int test_string(void)
+{
+ char b[32];
+ char *s;
+ int i;
+ int err=0;
+
+ b[16]='a'; b[17]='b'; b[18]='c'; b[19]=0;
+ TEST(s, strcpy(b, b+16), b, "wrong return %p != %p");
+ TEST_S(s, "abc", "strcpy gave incorrect string");
+ TEST(s, strcpy(b+1, b+16), b+1, "wrong return %p != %p");
+ TEST_S(s, "abc", "strcpy gave incorrect string");
+ TEST(s, strcpy(b+2, b+16), b+2, "wrong return %p != %p");
+ TEST_S(s, "abc", "strcpy gave incorrect string");
+ TEST(s, strcpy(b+3, b+16), b+3, "wrong return %p != %p");
+ TEST_S(s, "abc", "strcpy gave incorrect string");
+
+ TEST(s, strcpy(b+1, b+17), b+1, "wrong return %p != %p");
+ TEST_S(s, "bc", "strcpy gave incorrect string");
+ TEST(s, strcpy(b+2, b+18), b+2, "wrong return %p != %p");
+ TEST_S(s, "c", "strcpy gave incorrect string");
+ TEST(s, strcpy(b+3, b+19), b+3, "wrong return %p != %p");
+ TEST_S(s, "", "strcpy gave incorrect string");
+
+ TEST(s, memset(b, 'x', sizeof b), b, "wrong return %p != %p");
+ TEST(s, strncpy(b, "abc", sizeof b - 1), b, "wrong return %p != %p");
+ TEST(i, memcmp(b, "abc\0\0\0\0", 8), 0, "strncpy fails to zero-pad dest");
+ TEST(i, b[sizeof b - 1], 'x', "strncpy overruns buffer when n > strlen(src)");
+
+ b[3] = 'x'; b[4] = 0;
+ strncpy(b, "abc", 3);
+ TEST(i, b[2], 'c', "strncpy fails to copy last byte: %hhu != %hhu");
+ TEST(i, b[3], 'x', "strncpy overruns buffer to null-terminate: %hhu != %hhu");
+
+ TEST(i, !strncmp("abcd", "abce", 3), 1, "strncmp compares past n");
+ TEST(i, !!strncmp("abc", "abd", 3), 1, "strncmp fails to compare n-1st byte");
+
+ strcpy(b, "abc");
+ TEST(s, strncat(b, "123456", 3), b, "%p != %p");
+ TEST(i, b[6], 0, "strncat failed to null-terminate (%d)");
+ TEST_S(s, "abc123", "strncat gave incorrect string");
+
+ strcpy(b, "aaababccdd0001122223");
+ TEST(s, strchr(b, 'b'), b+3, "%p != %p");
+ TEST(s, strrchr(b, 'b'), b+5, "%p != %p");
+ TEST(i, strspn(b, "abcd"), 10, "%d != %d");
+ TEST(i, strcspn(b, "0123"), 10, "%d != %d");
+ TEST(s, strpbrk(b, "0123"), b+10, "%d != %d");
+
+ strcpy(b, "abc 123; xyz; foo");
+ TEST(s, strtok(b, " "), b, "%p != %p");
+ TEST_S(s, "abc", "strtok result");
+
+ TEST(s, strtok(NULL, ";"), b+4, "%p != %p");
+ TEST_S(s, " 123", "strtok result");
+
+ TEST(s, strtok(NULL, " ;"), b+11, "%p != %p");
+ TEST_S(s, "xyz", "strtok result");
+
+ TEST(s, strtok(NULL, " ;"), b+16, "%p != %p");
+ TEST_S(s, "foo", "strtok result");
+
+#ifdef HAVE_BSD_STRL
+ memset(b, 'x', sizeof b);
+ TEST(i, strlcpy(b, "abc", sizeof b - 1), 3, "length %d != %d");
+ TEST(i, b[3], 0, "strlcpy did not null-terminate short string (%d)");
+ TEST(i, b[4], 'x', "strlcpy wrote extra bytes (%d)");
+
+ memset(b, 'x', sizeof b);
+ TEST(i, strlcpy(b, "abc", 2), 3, "length %d != %d");
+ TEST(i, b[0], 'a', "strlcpy did not copy character %d");
+ TEST(i, b[1], 0, "strlcpy did not null-terminate long string (%d)");
+
+ memset(b, 'x', sizeof b);
+ TEST(i, strlcpy(b, "abc", 3), 3, "length %d != %d");
+ TEST(i, b[2], 0, "strlcpy did not null-terminate l-length string (%d)");
+
+ TEST(i, strlcpy(NULL, "abc", 0), 3, "length %d != %d");
+
+ memcpy(b, "abc\0\0\0x\0", 8);
+ TEST(i, strlcat(b, "123", sizeof b), 6, "length %d != %d");
+ TEST_S(b, "abc123", "strlcat result");
+
+ memcpy(b, "abc\0\0\0x\0", 8);
+ TEST(i, strlcat(b, "123", 6), 6, "length %d != %d");
+ TEST_S(b, "abc12", "strlcat result");
+ TEST(i, b[6], 'x', "strlcat wrote past string %d != %d");
+
+ memcpy(b, "abc\0\0\0x\0", 8);
+ TEST(i, strlcat(b, "123", 4), 6, "length %d != %d");
+ TEST_S(b, "abc", "strlcat result");
+
+ memcpy(b, "abc\0\0\0x\0", 8);
+ TEST(i, strlcat(b, "123", 3), 6, "length %d != %d");
+ TEST_S(b, "abc", "strlcat result");
+#endif
+
+ return err;
+}
+
diff --git a/strtod.c b/strtod.c
new file mode 100644
index 0000000..ef931d4
--- /dev/null
+++ b/strtod.c
@@ -0,0 +1,40 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <math.h>
+
+/* r = place to store result
+ * f = function call to test (or any expression)
+ * x = expected result
+ * m = message to print on failure (with formats for r & x)
+**/
+
+#define TEST(r, f, x, m) ( \
+msg = #f, ((r) = (f)) == (x) || \
+(printf(__FILE__ ":%d: %s failed (" m ")\n", __LINE__, #f, r, x, r-x), err++, 0) )
+
+#define TEST2(r, f, x, m) ( \
+((r) = (f)) == (x) || \
+(printf(__FILE__ ":%d: %s failed (" m ")\n", __LINE__, msg, r, x), err++, 0) )
+
+int test_strtod(void)
+{
+ int i;
+ double d, d2;
+ char buf[1000];
+ char *msg="";
+ int err=0;
+ char *s, *c;
+
+ for (i=0; i<100; i++) {
+ d = sin(i);
+ snprintf(buf, sizeof buf, "%.300f", d);
+ TEST(d2, strtod(buf, 0), d, "round trip fail %a != %a (%a)");
+ }
+
+ TEST(d, strtod("0x1p4", 0), 16.0, "hex float %a != %a");
+ TEST(d, strtod("0x1.1p4", 0), 17.0, "hex float %a != %a");
+
+ return err;
+}
diff --git a/strtol.c b/strtol.c
new file mode 100644
index 0000000..9ccee53
--- /dev/null
+++ b/strtol.c
@@ -0,0 +1,86 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+/* r = place to store result
+ * f = function call to test (or any expression)
+ * x = expected result
+ * m = message to print on failure (with formats for r & x)
+**/
+
+#define TEST(r, f, x, m) ( \
+msg = #f, ((r) = (f)) == (x) || \
+(printf(__FILE__ ":%d: %s failed (" m ")\n", __LINE__, #f, r, x), err++, 0) )
+
+#define TEST2(r, f, x, m) ( \
+((r) = (f)) == (x) || \
+(printf(__FILE__ ":%d: %s failed (" m ")\n", __LINE__, msg, r, x), err++, 0) )
+
+int test_strtol(void)
+{
+ int i;
+ long l;
+ unsigned long ul;
+ long long ll;
+ unsigned long long ull;
+ char *msg="";
+ int err=0;
+ char *s, *c;
+
+ TEST(l, atol("2147483647"), 2147483647L, "max 32bit signed %ld != %ld");
+
+ TEST(l, strtol("2147483647", 0, 0), 2147483647L, "max 32bit signed %ld != %ld");
+ TEST(ul, strtoul("4294967295", 0, 0), 4294967295UL, "max 32bit unsigned %lu != %lu");
+
+ if (sizeof(long) == 4) {
+ errno = 0;
+ TEST(l, strtol(s="2147483648", &c, 0), 2147483647L, "uncaught overflow %ld != %ld");
+ TEST2(i, c-s, 10, "wrong final position %d != %d");
+ TEST2(i, errno, ERANGE, "missing errno %d != %d");
+ errno = 0;
+ TEST(l, strtol(s="-2147483649", &c, 0), -2147483647L-1, "uncaught overflow %ld != %ld");
+ TEST2(i, c-s, 11, "wrong final position %d != %d");
+ TEST2(i, errno, ERANGE, "missing errno %d != %d");
+ errno = 0;
+ TEST(ul, strtoul(s="4294967296", &c, 0), 4294967295UL, "uncaught overflow %lu != %lu");
+ TEST2(i, c-s, 10, "wrong final position %d != %d");
+ TEST2(i, errno, ERANGE, "missing errno %d != %d");
+ errno = 0;
+ TEST(ul, strtoul(s="-1", &c, 0), 4294967295UL, "uncaught overflow %lu != %lu");
+ TEST2(i, c-s, 2, "wrong final position %d != %d");
+ TEST2(i, errno, ERANGE, "missing errno %d != %d");
+ errno = 0;
+ TEST(ul, strtoul(s="-2", &c, 0), 4294967295UL, "uncaught overflow %lu != %lu");
+ TEST2(i, c-s, 2, "wrong final position %d != %d");
+ TEST2(i, errno, ERANGE, "missing errno %d != %d");
+ errno = 0;
+ TEST(ul, strtoul(s="-2147483648", &c, 0), 4294967295UL, "uncaught overflow %lu != %lu");
+ TEST2(i, c-s, 11, "wrong final position %d != %d");
+ TEST2(i, errno, ERANGE, "missing errno %d != %d");
+ errno = 0;
+ TEST(ul, strtoul(s="-2147483649", &c, 0), 4294967295UL, "uncaught overflow %lu != %lu");
+ TEST2(i, c-s, 11, "wrong final position %d != %d");
+ TEST2(i, errno, ERANGE, "missing errno %d != %d");
+ } else {
+ TEST(i, 0, 1, "64bit tests not implemented");
+ }
+
+ TEST(l, strtol("z", 0, 36), 35, "%ld != %ld");
+ TEST(l, strtol("00010010001101000101011001111000", 0, 2), 0x12345678, "%ld != %ld");
+ TEST(l, strtol(s="0F5F", &c, 16), 0x0f5f, "%ld != %ld");
+
+ TEST(l, strtol(s="0xz", &c, 16), 0, "%ld != %ld");
+ TEST2(i, c-s, 1, "wrong final position %ld != %ld");
+
+ TEST(l, strtol(s="0x1234", &c, 16), 0x1234, "%ld != %ld");
+ TEST2(i, c-s, 6, "wrong final position %ld != %ld");
+
+ errno = 0;
+ c = NULL;
+ TEST(l, strtol(s="123", &c, 37), 0, "%ld != %ld");
+ TEST2(i, c-s, 0, "wrong final position %d != %d");
+ TEST2(i, errno, EINVAL, "%d != %d");
+
+ return err;
+}
diff --git a/testsuite.c b/testsuite.c
new file mode 100644
index 0000000..3d80b36
--- /dev/null
+++ b/testsuite.c
@@ -0,0 +1,38 @@
+#include <stdio.h>
+
+#define RUN_TEST(a) { \
+extern int test_ ##a (void); \
+int e = test_ ##a (); \
+if (e) printf("%s test failed, %d error(s)\n", #a, e); \
+else printf("%s test passed\n", #a); \
+err += e; \
+}
+
+int main()
+{
+ int err=0;
+
+ RUN_TEST(fdopen);
+ RUN_TEST(fnmatch);
+ RUN_TEST(fscanf);
+ RUN_TEST(popen);
+ RUN_TEST(qsort);
+ RUN_TEST(time);
+ RUN_TEST(sscanf);
+ RUN_TEST(snprintf);
+ RUN_TEST(string);
+ RUN_TEST(strtod);
+ RUN_TEST(strtol);
+ RUN_TEST(ungetc);
+ RUN_TEST(wcstol);
+ RUN_TEST(basename);
+ RUN_TEST(dirname);
+ RUN_TEST(mbc);
+ RUN_TEST(sem);
+ RUN_TEST(pthread);
+ /* env is last because it will break subsequent tests */
+ RUN_TEST(env);
+
+ printf("\ntotal errors: %d\n", err);
+ return !!err;
+}
diff --git a/time.c b/time.c
new file mode 100644
index 0000000..c722755
--- /dev/null
+++ b/time.c
@@ -0,0 +1,76 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+
+/* We use this instead of memcmp because some broken C libraries
+ * add additional nonstandard fields to struct tm... */
+
+int tm_cmp(struct tm tm1, struct tm tm2)
+{
+ return tm1.tm_sec != tm2.tm_sec ||
+ tm1.tm_min != tm2.tm_min ||
+ tm1.tm_hour != tm2.tm_hour ||
+ tm1.tm_mday != tm2.tm_mday ||
+ tm1.tm_mon != tm2.tm_mon ||
+ tm1.tm_year != tm2.tm_year ||
+ tm1.tm_wday != tm2.tm_wday ||
+ tm1.tm_yday != tm2.tm_yday ||
+ tm1.tm_isdst!= tm2.tm_isdst;
+}
+
+char *tm_str(struct tm tm)
+{
+ static int i;
+ static char b[4][64];
+ i = (i+1)%4;
+ snprintf(b[i], sizeof b[i],
+ "s=%02d m=%02d h=%02d mday=%02d mon=%02d year=%04d wday=%d yday=%d isdst=%d",
+ tm.tm_sec, tm.tm_min, tm.tm_hour,
+ tm.tm_mday, tm.tm_mon, tm.tm_year,
+ tm.tm_wday, tm.tm_yday, tm.tm_isdst);
+ return b[i];
+}
+
+#define TM(ss,mm,hh,md,mo,yr,wd,yd,dst) (struct tm){ \
+ .tm_sec = ss, .tm_min = mm, .tm_hour = hh, \
+ .tm_mday = md, .tm_mon = mo, .tm_year = yr, \
+ .tm_wday = wd, .tm_yday = yd, .tm_isdst = dst }
+
+#define TM_EPOCH TM(0,0,0,1,0,70,4,0,0)
+#define TM_Y2038_1S TM(7,14,3,19,0,138,2,18,0)
+#define TM_Y2038 TM(8,14,3,19,0,138,2,18,0)
+
+#define TEST_TM(r,x,m) (!tm_cmp((r),(x)) || \
+(printf(__FILE__ ":%d: %s failed:\n\tresult: %s\n\texpect: %s\n", __LINE__, \
+m, tm_str((r)), tm_str((x))), err++, 0) )
+
+#define TEST(r, f, x, m) ( \
+((r) = (f)) == (x) || \
+(printf(__FILE__ ":%d: %s failed (" m ")\n", __LINE__, #f, r, x), err++, 0) )
+
+int test_time(void)
+{
+ struct tm tm, *tm_p;
+ time_t t;
+ int err=0;
+
+ putenv("TZ=GMT");
+ tzset();
+
+ t=0; tm_p = gmtime(&t);
+ TEST_TM(*tm_p, TM_EPOCH, "gmtime(0)");
+
+ tm = TM_Y2038_1S;
+ t = mktime(&tm);
+ tm = *(gmtime(&t));
+ TEST_TM(*tm_p, TM_Y2038_1S, "mktime/gmtime(Y2038-1)");
+
+ tm = TM_Y2038;
+ t = mktime(&tm);
+ tm = *(gmtime(&t));
+ TEST_TM(*tm_p, TM_Y2038, "mktime/gmtime(Y2038)");
+
+ /* FIXME: set a TZ var and check DST boundary conditions */
+
+ return err;
+}
diff --git a/ungetc.c b/ungetc.c
new file mode 100644
index 0000000..070ad92
--- /dev/null
+++ b/ungetc.c
@@ -0,0 +1,55 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+
+#define TEST(r, f, x, m) ( \
+((r) = (f)) == (x) || \
+(printf(__FILE__ ":%d: %s failed (" m ")\n", __LINE__, #f, r, x, strerror(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) )
+
+int test_ungetc(void)
+{
+ int i;
+ int err=0;
+ char a[100], b[100], *s;
+ FILE *f;
+
+ TEST(i, !(f = tmpfile()), 0, "failed to create temp file %d!=%d (%s)");
+
+ if (!f) return err;
+
+ errno=0;
+ TEST(i, fprintf(f, "hello, world\n"), 13, "%d != %d (%m)");
+ TEST(i, fseek(f, 0, SEEK_SET), 0, "%d != %d (%m)");
+
+ TEST(i, feof(f), 0, "%d != %d");
+ TEST(i, fgetc(f), 'h', "'%c' != '%c'");
+ TEST(i, ftell(f), 1, "%d != %d");
+ TEST(i, ungetc('x', f), 'x', "%d != %d");
+ TEST(i, ftell(f), 0, "%d != %d");
+ TEST(i, fscanf(f, "%[h]", a), 0, "got %d fields, expected %d");
+ TEST(i, ftell(f), 0, "%d != %d");
+ TEST(i, fgetc(f), 'x', "'%c' != '%c'");
+ TEST(i, ftell(f), 1, "%d != %d");
+
+ TEST(i, fseek(f, 0, SEEK_SET), 0, "%d != %d");
+ TEST(i, ungetc('x', f), 'x', "%d != %d");
+ TEST(i, fread(a, 1, sizeof a, f), 14, "read %d, expected %d");
+ a[14] = 0;
+ TEST_S(a, "xhello, world\n", "mismatch reading ungot character");
+
+ TEST(i, fseek(f, 0, SEEK_SET), 0, "%d != %d");
+ TEST(i, fscanf(f, "%[x]", a), 0, "got %d fields, expected %d");
+ TEST(i, ungetc('x', f), 'x', "unget failed after fscanf: %d != %d");
+ TEST(i, fgetc(f), 'x', "'%c' != '%c'");
+ TEST(i, fgetc(f), 'h', "'%c' != '%c'");
+
+ fclose(f);
+
+ return err;
+}
diff --git a/wcstol.c b/wcstol.c
new file mode 100644
index 0000000..07113df
--- /dev/null
+++ b/wcstol.c
@@ -0,0 +1,78 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <wchar.h>
+
+#define TEST(r, f, x, m) ( \
+msg = #f, ((r) = (f)) == (x) || \
+(printf(__FILE__ ":%d: %s failed (" m ")\n", __LINE__, #f, r, x), err++, 0) )
+
+#define TEST2(r, f, x, m) ( \
+((r) = (f)) == (x) || \
+(printf(__FILE__ ":%d: %s failed (" m ")\n", __LINE__, msg, r, x), err++, 0) )
+
+int test_wcstol(void)
+{
+ int i;
+ long l;
+ unsigned long ul;
+ long long ll;
+ unsigned long long ull;
+ char *msg="";
+ int err=0;
+ wchar_t *s, *c;
+
+ TEST(l, wcstol(L"2147483647", 0, 0), 2147483647L, "max 32bit signed %ld != %ld");
+ TEST(ul, wcstoul(L"4294967295", 0, 0), 4294967295UL, "max 32bit unsigned %lu != %lu");
+
+ if (sizeof(long) == 4) {
+ errno = 0;
+ TEST(l, wcstol(s=L"2147483648", &c, 0), 2147483647L, "uncaught overflow %ld != %ld");
+ TEST2(i, c-s, 10, "wrong final position %d != %d");
+ TEST2(i, errno, ERANGE, "missing errno %d != %d");
+ errno = 0;
+ TEST(l, wcstol(s=L"-2147483649", &c, 0), -2147483647L-1, "uncaught overflow %ld != %ld");
+ TEST2(i, c-s, 11, "wrong final position %d != %d");
+ TEST2(i, errno, ERANGE, "missing errno %d != %d");
+ errno = 0;
+ TEST(ul, wcstoul(s=L"4294967296", &c, 0), 4294967295UL, "uncaught overflow %lu != %lu");
+ TEST2(i, c-s, 10, "wrong final position %d != %d");
+ TEST2(i, errno, ERANGE, "missing errno %d != %d");
+ errno = 0;
+ TEST(ul, wcstoul(s=L"-1", &c, 0), 4294967295UL, "uncaught overflow %lu != %lu");
+ TEST2(i, c-s, 2, "wrong final position %d != %d");
+ TEST2(i, errno, ERANGE, "missing errno %d != %d");
+ errno = 0;
+ TEST(ul, wcstoul(s=L"-2", &c, 0), 4294967295UL, "uncaught overflow %lu != %lu");
+ TEST2(i, c-s, 2, "wrong final position %d != %d");
+ TEST2(i, errno, ERANGE, "missing errno %d != %d");
+ errno = 0;
+ TEST(ul, wcstoul(s=L"-2147483648", &c, 0), 4294967295UL, "uncaught overflow %lu != %lu");
+ TEST2(i, c-s, 11, "wrong final position %d != %d");
+ TEST2(i, errno, ERANGE, "missing errno %d != %d");
+ errno = 0;
+ TEST(ul, wcstoul(s=L"-2147483649", &c, 0), 4294967295UL, "uncaught overflow %lu != %lu");
+ TEST2(i, c-s, 11, "wrong final position %d != %d");
+ TEST2(i, errno, ERANGE, "missing errno %d != %d");
+ } else {
+ TEST(i, 0, 1, "64bit tests not implemented");
+ }
+
+ TEST(l, wcstol(L"z", 0, 36), 35, "%ld != %ld");
+ TEST(l, wcstol(L"00010010001101000101011001111000", 0, 2), 0x12345678, "%ld != %ld");
+
+ TEST(l, wcstol(s=L"0xz", &c, 16), 0, "%ld != %ld");
+ TEST2(i, c-s, 1, "wrong final position %ld != %ld");
+
+ TEST(l, wcstol(s=L"0x1234", &c, 16), 0x1234, "%ld != %ld");
+ TEST2(i, c-s, 6, "wrong final position %ld != %ld");
+
+ errno = 0;
+ c = NULL;
+ TEST(l, wcstol(s=L"123", &c, 37), 0, "%ld != %ld");
+ TEST2(i, c-s, 0, "wrong final position %d != %d");
+ TEST2(i, errno, EINVAL, "%d != %d");
+
+ return err;
+}