From a9baddd7d07b9fe15e212985a808a79773ec72e4 Mon Sep 17 00:00:00 2001 From: Rich Felker Date: Sat, 19 Mar 2011 22:26:06 -0400 Subject: initial check-in, taken from old libc svn repo with significant additions --- Makefile | 29 ++++++ README | 32 +++++++ basename.c | 30 ++++++ config.mak | 3 + dirname.c | 32 +++++++ env.c | 40 ++++++++ fdopen.c | 40 ++++++++ fnmatch.c | 142 ++++++++++++++++++++++++++++ fscanf.c | 47 ++++++++++ hello.old | 308 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ mbc.c | 92 ++++++++++++++++++ popen.c | 51 ++++++++++ pthread.c | 161 +++++++++++++++++++++++++++++++ qsort.c | 59 ++++++++++++ sem.c | 52 ++++++++++ snprintf.c | 120 +++++++++++++++++++++++ sscanf.c | 90 ++++++++++++++++++ string.c | 118 +++++++++++++++++++++++ strtod.c | 40 ++++++++ strtol.c | 86 +++++++++++++++++ testsuite.c | 38 ++++++++ time.c | 76 +++++++++++++++ ungetc.c | 55 +++++++++++ wcstol.c | 78 +++++++++++++++ 24 files changed, 1819 insertions(+) create mode 100644 Makefile create mode 100644 README create mode 100644 basename.c create mode 100644 config.mak create mode 100644 dirname.c create mode 100644 env.c create mode 100644 fdopen.c create mode 100644 fnmatch.c create mode 100644 fscanf.c create mode 100644 hello.old create mode 100644 mbc.c create mode 100644 popen.c create mode 100644 pthread.c create mode 100644 qsort.c create mode 100644 sem.c create mode 100644 snprintf.c create mode 100644 sscanf.c create mode 100644 string.c create mode 100644 strtod.c create mode 100644 strtol.c create mode 100644 testsuite.c create mode 100644 time.c create mode 100644 ungetc.c create mode 100644 wcstol.c 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 +#include +#include +#include + +#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 +#include +#include +#include + +#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 +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include + +#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 +#include +#include +#include + +/* 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 +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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; jpw_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 +#include +#include +#include +#include +#include + +/* 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 +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include + +#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 +#include +#include + +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 0) { + FAIL("string sort"); + for (i=0; i n[i+1]) { + FAIL("integer sort"); + for (i=0; i +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include + +#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 +#include +#include +#include + +#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 +#include + +/* 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 +#include +#include +#include +#include + +/* 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 +#include +#include +#include + +/* 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 + +#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 +#include +#include + +/* 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 +#include +#include +#include +#include + +#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 +#include +#include +#include +#include + +#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; +} -- cgit v1.2.1