Module Name:    src
Committed By:   pgoyette
Date:           Fri Jan  7 15:05:58 UTC 2011

Modified Files:
        src/tests/lib/libc: Makefile
Added Files:
        src/tests/lib/libc/db: Makefile README h_db.c t_db.sh

Log Message:
Atf-ify the db tests.

XXX Note that the original regress version of this test did not run the
XXX btree_delete test; that test is broken, and is disabled for now.


To generate a diff of this commit:
cvs rdiff -u -r1.23 -r1.24 src/tests/lib/libc/Makefile
cvs rdiff -u -r0 -r1.1 src/tests/lib/libc/db/Makefile \
    src/tests/lib/libc/db/README src/tests/lib/libc/db/h_db.c \
    src/tests/lib/libc/db/t_db.sh

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/tests/lib/libc/Makefile
diff -u src/tests/lib/libc/Makefile:1.23 src/tests/lib/libc/Makefile:1.24
--- src/tests/lib/libc/Makefile:1.23	Fri Jan  7 02:47:40 2011
+++ src/tests/lib/libc/Makefile	Fri Jan  7 15:05:57 2011
@@ -1,9 +1,9 @@
-# $NetBSD: Makefile,v 1.23 2011/01/07 02:47:40 pgoyette Exp $
+# $NetBSD: Makefile,v 1.24 2011/01/07 15:05:57 pgoyette Exp $
 
 .include <bsd.own.mk>
 .include <bsd.sys.mk>
 
-TESTS_SUBDIRS+=	gen hash ieeefp setjmp stdlib stdio string ttyio
+TESTS_SUBDIRS+=	db gen hash ieeefp setjmp stdlib stdio string ttyio
 
 .if ${HAS_SSP} == "yes"
 TESTS_SUBDIRS+=	ssp

Added files:

Index: src/tests/lib/libc/db/Makefile
diff -u /dev/null src/tests/lib/libc/db/Makefile:1.1
--- /dev/null	Fri Jan  7 15:05:58 2011
+++ src/tests/lib/libc/db/Makefile	Fri Jan  7 15:05:58 2011
@@ -0,0 +1,18 @@
+# $NetBSD: Makefile,v 1.1 2011/01/07 15:05:58 pgoyette Exp $
+
+.include <bsd.own.mk>
+
+TESTSDIR=	${TESTSBASE}/lib/libc/db
+
+TESTS_SH+=	t_db
+
+BINDIR=		${TESTSDIR}
+MKMAN=		no
+
+PROGS+=		h_db
+
+FILESDIR=	${TESTSDIR}
+
+FILES+=		README
+
+.include <bsd.test.mk>
Index: src/tests/lib/libc/db/README
diff -u /dev/null src/tests/lib/libc/db/README:1.1
--- /dev/null	Fri Jan  7 15:05:58 2011
+++ src/tests/lib/libc/db/README	Fri Jan  7 15:05:58 2011
@@ -0,0 +1,66 @@
+#	$NetBSD: README,v 1.1 2011/01/07 15:05:58 pgoyette Exp $
+#	@(#)README	8.8 (Berkeley) 7/31/94
+
+Fairly large files (the command files) are built in this directory during
+the test runs, and even larger files (the database files) are created in
+"/var/tmp".  If the latter directory doesn't exist, set the environmental
+variable TMPDIR to a directory where the files can be built.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+The script file consists of lines with an initial character which is
+the command for that line, or an initial character indicating a key
+or data entry for a previous command.
+
+Legal command characters are as follows:
+
+c: compare a record
+	+ must be followed by [kK][dD]; the data value in the database
+	  associated with the specified key is compared to the specified
+	  data value.
+e: echo a string
+	+ writes out the rest of the line into the output file; if the
+	  last character is not a carriage-return, a newline is appended.
+f: set the flags for the next command
+	+ no value zero's the flags
+g: do a get command
+	+ must be followed by [kK]
+	+ writes out the retrieved data DBT.
+o [r]: dump [reverse]
+	+ dump the database out, if 'r' is set, in reverse order.
+p: do a put command
+	+ must be followed by [kK][dD]
+r: do a del command
+	+ must be followed by [kK] unless R_CURSOR flag set.
+S: sync the database
+s: do a seq command
+	+ must be followed by [kK] if R_CURSOR flag set.
+	+ writes out the retrieved data DBT.
+
+Legal key/data characters are as follows:
+
+D [file]: data file
+	+ set the current data value to the contents of the file
+d [data]:
+	+ set the current key value to the contents of the line.
+K [file]: key file
+	+ set the current key value to the contents of the file
+k [data]:
+	+ set the current key value to the contents of the line.
+
+Blank lines, lines with leading white space, and lines with leading
+hash marks (#) are ignored.
+
+Options to dbtest are as follows:
+
+	-d: Set the DB_LOCK flag.
+	-f: Use the file argument as the database file.
+	-i: Use the rest of the argument to set elements in the info
+	    structure.  If the type is btree, then "-i cachesize=10240"
+	    will set BTREEINFO.cachesize to 10240.
+	-o: The rest of the argument is the output file instead of
+	    using stdout.
+	-s: Don't delete the database file before opening it, i.e.
+	    use the database file from a previous run.
+
+Dbtest requires two arguments, the type of access "hash", "recno"
+or "btree", and the script name or "-" to indicate stdin.
Index: src/tests/lib/libc/db/h_db.c
diff -u /dev/null src/tests/lib/libc/db/h_db.c:1.1
--- /dev/null	Fri Jan  7 15:05:58 2011
+++ src/tests/lib/libc/db/h_db.c	Fri Jan  7 15:05:58 2011
@@ -0,0 +1,731 @@
+/*	$NetBSD: h_db.c,v 1.1 2011/01/07 15:05:58 pgoyette Exp $	*/
+
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1992, 1993, 1994\
+	The Regents of the University of California.  All rights reserved.");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)dbtest.c	8.17 (Berkeley) 9/1/94";
+#else
+__RCSID("$NetBSD: h_db.c,v 1.1 2011/01/07 15:05:58 pgoyette Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <err.h>
+#include <db.h>
+
+enum S { COMMAND, COMPARE, GET, PUT, REMOVE, SEQ, SEQFLAG, KEY, DATA };
+
+static void	 compare(DBT *, DBT *);
+static DBTYPE	 dbtype(const char *);
+static void	 dump(DB *, int);
+static void	 get(DB *, DBT *);
+static void	 getdata(DB *, DBT *, DBT *);
+static void	 put(DB *, DBT *, DBT *);
+static void	 rem(DB *, DBT *);
+static const char *sflags(int);
+static void	 synk(DB *);
+static void	*rfile(char *, size_t *);
+static void	 seq(DB *, DBT *);
+static u_int	 setflags(char *);
+static void	*setinfo(DBTYPE, char *);
+static void	 usage(void) __attribute__((__noreturn__));
+static void	*xcopy(void *, size_t);
+static void	 chkcmd(enum S);
+static void	 chkdata(enum S);
+static void	 chkkey(enum S);
+
+#ifdef STATISTICS
+extern void __bt_stat(DB *);
+#endif
+
+static DBTYPE type;			/* Database type. */
+static void *infop;			/* Iflags. */
+static size_t lineno;			/* Current line in test script. */
+static u_int flags;				/* Current DB flags. */
+static int ofd = STDOUT_FILENO;		/* Standard output fd. */
+
+static DB *XXdbp;			/* Global for gdb. */
+static size_t XXlineno;			/* Fast breakpoint for gdb. */
+
+int
+main(int argc, char *argv[])
+{
+	extern int optind;
+	extern char *optarg;
+	enum S command = COMMAND, state;
+	DB *dbp;
+	DBT data, key, keydata;
+	size_t len;
+	int ch, oflags, sflag;
+	char *fname, *infoarg, *p, *t, buf[8 * 1024];
+	bool unlink_dbfile;
+
+	infoarg = NULL;
+	fname = NULL;
+	unlink_dbfile = false;
+	oflags = O_CREAT | O_RDWR;
+	sflag = 0;
+	while ((ch = getopt(argc, argv, "f:i:lo:s")) != -1)
+		switch (ch) {
+		case 'f':
+			fname = optarg;
+			break;
+		case 'i':
+			infoarg = optarg;
+			break;
+		case 'l':
+			oflags |= DB_LOCK;
+			break;
+		case 'o':
+			if ((ofd = open(optarg,
+			    O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
+				err(1, "Cannot create `%s'", optarg);
+			break;
+		case 's':
+			sflag = 1;
+			break;
+		case '?':
+		default:
+			usage();
+		}
+	argc -= optind;
+	argv += optind;
+
+	if (argc != 2)
+		usage();
+
+	/* Set the type. */
+	type = dbtype(*argv++);
+
+	/* Open the descriptor file. */
+        if (strcmp(*argv, "-") && freopen(*argv, "r", stdin) == NULL)
+	    err(1, "Cannot reopen `%s'", *argv);
+
+	/* Set up the db structure as necessary. */
+	if (infoarg == NULL)
+		infop = NULL;
+	else
+		for (p = strtok(infoarg, ",\t "); p != NULL;
+		    p = strtok(0, ",\t "))
+			if (*p != '\0')
+				infop = setinfo(type, p);
+
+	/*
+	 * Open the DB.  Delete any preexisting copy, you almost never
+	 * want it around, and it often screws up tests.
+	 */
+	if (fname == NULL) {
+		const char *q = getenv("TMPDIR");
+		if (q == NULL)
+			q = "/var/tmp";
+		(void)snprintf(buf, sizeof(buf), "%s/__dbtest", q);
+		fname = buf;
+		(void)unlink(buf);
+		unlink_dbfile = true;
+	} else  if (!sflag)
+		(void)unlink(fname);
+
+	if ((dbp = dbopen(fname,
+	    oflags, S_IRUSR | S_IWUSR, type, infop)) == NULL)
+		err(1, "Cannot dbopen `%s'", fname);
+	XXdbp = dbp;
+	if (unlink_dbfile)
+		(void)unlink(fname);
+
+	state = COMMAND;
+	for (lineno = 1;
+	    (p = fgets(buf, sizeof(buf), stdin)) != NULL; ++lineno) {
+		/* Delete the newline, displaying the key/data is easier. */
+		if (ofd == STDOUT_FILENO && (t = strchr(p, '\n')) != NULL)
+			*t = '\0';
+		if ((len = strlen(buf)) == 0 || isspace((unsigned char)*p) ||
+		    *p == '#')
+			continue;
+
+		/* Convenient gdb break point. */
+		if (XXlineno == lineno)
+			XXlineno = 1;
+		switch (*p) {
+		case 'c':			/* compare */
+			chkcmd(state);
+			state = KEY;
+			command = COMPARE;
+			break;
+		case 'e':			/* echo */
+			chkcmd(state);
+			/* Don't display the newline, if CR at EOL. */
+			if (p[len - 2] == '\r')
+				--len;
+			if (write(ofd, p + 1, len - 1) != (ssize_t)len - 1 ||
+			    write(ofd, "\n", 1) != 1)
+				err(1, "write failed");
+			break;
+		case 'g':			/* get */
+			chkcmd(state);
+			state = KEY;
+			command = GET;
+			break;
+		case 'p':			/* put */
+			chkcmd(state);
+			state = KEY;
+			command = PUT;
+			break;
+		case 'r':			/* remove */
+			chkcmd(state);
+                        if (flags == R_CURSOR) {
+				rem(dbp, &key);
+				state = COMMAND;
+                        } else {
+				state = KEY;
+				command = REMOVE;
+			}
+			break;
+		case 'S':			/* sync */
+			chkcmd(state);
+			synk(dbp);
+			state = COMMAND;
+			break;
+		case 's':			/* seq */
+			chkcmd(state);
+			if (flags == R_CURSOR) {
+				state = KEY;
+				command = SEQ;
+			} else
+				seq(dbp, &key);
+			break;
+		case 'f':
+			flags = setflags(p + 1);
+			break;
+		case 'D':			/* data file */
+			chkdata(state);
+			data.data = rfile(p + 1, &data.size);
+			goto ldata;
+		case 'd':			/* data */
+			chkdata(state);
+			data.data = xcopy(p + 1, len - 1);
+			data.size = len - 1;
+ldata:			switch (command) {
+			case COMPARE:
+				compare(&keydata, &data);
+				break;
+			case PUT:
+				put(dbp, &key, &data);
+				break;
+			default:
+				errx(1, "line %zu: command doesn't take data",
+				    lineno);
+			}
+			if (type != DB_RECNO)
+				free(key.data);
+			free(data.data);
+			state = COMMAND;
+			break;
+		case 'K':			/* key file */
+			chkkey(state);
+			if (type == DB_RECNO)
+				errx(1, "line %zu: 'K' not available for recno",
+				    lineno);
+			key.data = rfile(p + 1, &key.size);
+			goto lkey;
+		case 'k':			/* key */
+			chkkey(state);
+			if (type == DB_RECNO) {
+				static recno_t recno;
+				recno = atoi(p + 1);
+				key.data = &recno;
+				key.size = sizeof(recno);
+			} else {
+				key.data = xcopy(p + 1, len - 1);
+				key.size = len - 1;
+			}
+lkey:			switch (command) {
+			case COMPARE:
+				getdata(dbp, &key, &keydata);
+				state = DATA;
+				break;
+			case GET:
+				get(dbp, &key);
+				if (type != DB_RECNO)
+					free(key.data);
+				state = COMMAND;
+				break;
+			case PUT:
+				state = DATA;
+				break;
+			case REMOVE:
+				rem(dbp, &key);
+				if ((type != DB_RECNO) && (flags != R_CURSOR))
+					free(key.data);
+				state = COMMAND;
+				break;
+			case SEQ:
+				seq(dbp, &key);
+				if ((type != DB_RECNO) && (flags != R_CURSOR))
+					free(key.data);
+				state = COMMAND;
+				break;
+			default:
+				errx(1, "line %zu: command doesn't take a key",
+				    lineno);
+			}
+			break;
+		case 'o':
+			dump(dbp, p[1] == 'r');
+			break;
+		default:
+			errx(1, "line %zu: %s: unknown command character",
+			    lineno, p);
+		}
+	}
+#ifdef STATISTICS
+	/*
+	 * -l must be used (DB_LOCK must be set) for this to be
+	 * used, otherwise a page will be locked and it will fail.
+	 */
+	if (type == DB_BTREE && oflags & DB_LOCK)
+		__bt_stat(dbp);
+#endif
+	if ((*dbp->close)(dbp))
+		err(1, "db->close failed");
+	(void)close(ofd);
+	return 0;
+}
+
+#define	NOOVERWRITE	"put failed, would overwrite key\n"
+
+static void
+compare(DBT *db1, DBT *db2)
+{
+	size_t len;
+	u_char *p1, *p2;
+
+	if (db1->size != db2->size)
+		printf("compare failed: key->data len %zu != data len %zu\n",
+		    db1->size, db2->size);
+
+	len = MIN(db1->size, db2->size);
+	for (p1 = db1->data, p2 = db2->data; len--;)
+		if (*p1++ != *p2++) {
+			printf("compare failed at offset %lu\n",
+			    (unsigned long)(p1 - (u_char *)db1->data));
+			break;
+		}
+}
+
+static void
+get(DB *dbp, DBT *kp)
+{
+	DBT data;
+
+	switch ((*dbp->get)(dbp, kp, &data, flags)) {
+	case 0:
+		(void)write(ofd, data.data, data.size);
+		if (ofd == STDOUT_FILENO)
+			(void)write(ofd, "\n", 1);
+		break;
+	case -1:
+		err(1, "line %zu: get failed", lineno);
+		/* NOTREACHED */
+	case 1:
+#define	NOSUCHKEY	"get failed, no such key\n"
+		if (ofd != STDOUT_FILENO)
+			(void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1);
+		else
+			(void)fprintf(stderr, "%zu: %.*s: %s",
+			    lineno, (int)MIN(kp->size, 20),
+			    (const char *)kp->data,
+			    NOSUCHKEY);
+#undef	NOSUCHKEY
+		break;
+	}
+}
+
+static void
+getdata(DB *dbp, DBT *kp, DBT *dp)
+{
+	switch ((*dbp->get)(dbp, kp, dp, flags)) {
+	case 0:
+		return;
+	case -1:
+		err(1, "line %zu: getdata failed", lineno);
+		/* NOTREACHED */
+	case 1:
+		errx(1, "line %zu: getdata failed, no such key", lineno);
+		/* NOTREACHED */
+	}
+}
+
+static void
+put(DB *dbp, DBT *kp, DBT *dp)
+{
+	switch ((*dbp->put)(dbp, kp, dp, flags)) {
+	case 0:
+		break;
+	case -1:
+		err(1, "line %zu: put failed", lineno);
+		/* NOTREACHED */
+	case 1:
+		(void)write(ofd, NOOVERWRITE, sizeof(NOOVERWRITE) - 1);
+		break;
+	}
+}
+
+static void
+rem(DB *dbp, DBT *kp)
+{
+	switch ((*dbp->del)(dbp, kp, flags)) {
+	case 0:
+		break;
+	case -1:
+		err(1, "line %zu: rem failed", lineno);
+		/* NOTREACHED */
+	case 1:
+#define	NOSUCHKEY	"rem failed, no such key\n"
+		if (ofd != STDOUT_FILENO)
+			(void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1);
+		else if (flags != R_CURSOR)
+			(void)fprintf(stderr, "%zu: %.*s: %s", 
+			    lineno, (int)MIN(kp->size, 20),
+			    (const char *)kp->data, NOSUCHKEY);
+		else
+			(void)fprintf(stderr,
+			    "%zu: rem of cursor failed\n", lineno);
+#undef	NOSUCHKEY
+		break;
+	}
+}
+
+static void
+synk(DB *dbp)
+{
+	switch ((*dbp->sync)(dbp, flags)) {
+	case 0:
+		break;
+	case -1:
+		err(1, "line %zu: synk failed", lineno);
+		/* NOTREACHED */
+	}
+}
+
+static void
+seq(DB *dbp, DBT *kp)
+{
+	DBT data;
+
+	switch (dbp->seq(dbp, kp, &data, flags)) {
+	case 0:
+		(void)write(ofd, data.data, data.size);
+		if (ofd == STDOUT_FILENO)
+			(void)write(ofd, "\n", 1);
+		break;
+	case -1:
+		err(1, "line %zu: seq failed", lineno);
+		/* NOTREACHED */
+	case 1:
+#define	NOSUCHKEY	"seq failed, no such key\n"
+		if (ofd != STDOUT_FILENO)
+			(void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1);
+		else if (flags == R_CURSOR)
+			(void)fprintf(stderr, "%zu: %.*s: %s", 
+			    lineno, (int)MIN(kp->size, 20),
+			    (const char *)kp->data, NOSUCHKEY);
+		else
+			(void)fprintf(stderr,
+			    "%zu: seq (%s) failed\n", lineno, sflags(flags));
+#undef	NOSUCHKEY
+		break;
+	}
+}
+
+static void
+dump(DB *dbp, int rev)
+{
+	DBT key, data;
+	int xflags, nflags;
+
+	if (rev) {
+		xflags = R_LAST;
+		nflags = R_PREV;
+	} else {
+		xflags = R_FIRST;
+		nflags = R_NEXT;
+	}
+	for (;; xflags = nflags)
+		switch (dbp->seq(dbp, &key, &data, xflags)) {
+		case 0:
+			(void)write(ofd, data.data, data.size);
+			if (ofd == STDOUT_FILENO)
+				(void)write(ofd, "\n", 1);
+			break;
+		case 1:
+			goto done;
+		case -1:
+			err(1, "line %zu: (dump) seq failed", lineno);
+			/* NOTREACHED */
+		}
+done:	return;
+}
+	
+static u_int
+setflags(char *s)
+{
+	char *p;
+
+	for (; isspace((unsigned char)*s); ++s);
+	if (*s == '\n' || *s == '\0')
+		return 0;
+	if ((p = strchr(s, '\n')) != NULL)
+		*p = '\0';
+	if (!strcmp(s, "R_CURSOR"))		return R_CURSOR;
+	if (!strcmp(s, "R_FIRST"))		return R_FIRST;
+	if (!strcmp(s, "R_IAFTER")) 		return R_IAFTER;
+	if (!strcmp(s, "R_IBEFORE")) 		return R_IBEFORE;
+	if (!strcmp(s, "R_LAST")) 		return R_LAST;
+	if (!strcmp(s, "R_NEXT")) 		return R_NEXT;
+	if (!strcmp(s, "R_NOOVERWRITE"))	return R_NOOVERWRITE;
+	if (!strcmp(s, "R_PREV"))		return R_PREV;
+	if (!strcmp(s, "R_SETCURSOR"))		return R_SETCURSOR;
+
+	errx(1, "line %zu: %s: unknown flag", lineno, s);
+	/* NOTREACHED */
+}
+
+static const char *
+sflags(int xflags)
+{
+	switch (xflags) {
+	case R_CURSOR:		return "R_CURSOR";
+	case R_FIRST:		return "R_FIRST";
+	case R_IAFTER:		return "R_IAFTER";
+	case R_IBEFORE:		return "R_IBEFORE";
+	case R_LAST:		return "R_LAST";
+	case R_NEXT:		return "R_NEXT";
+	case R_NOOVERWRITE:	return "R_NOOVERWRITE";
+	case R_PREV:		return "R_PREV";
+	case R_SETCURSOR:	return "R_SETCURSOR";
+	}
+
+	return "UNKNOWN!";
+}
+	
+static DBTYPE
+dbtype(const char *s)
+{
+	if (!strcmp(s, "btree"))
+		return DB_BTREE;
+	if (!strcmp(s, "hash"))
+		return DB_HASH;
+	if (!strcmp(s, "recno"))
+		return DB_RECNO;
+	errx(1, "%s: unknown type (use btree, hash or recno)", s);
+	/* NOTREACHED */
+}
+
+static void *
+setinfo(DBTYPE dtype, char *s)
+{
+	static BTREEINFO ib;
+	static HASHINFO ih;
+	static RECNOINFO rh;
+	char *eq;
+
+	if ((eq = strchr(s, '=')) == NULL)
+		errx(1, "%s: illegal structure set statement", s);
+	*eq++ = '\0';
+	if (!isdigit((unsigned char)*eq))
+		errx(1, "%s: structure set statement must be a number", s);
+		
+	switch (dtype) {
+	case DB_BTREE:
+		if (!strcmp("flags", s)) {
+			ib.flags = atoi(eq);
+			return &ib;
+		}
+		if (!strcmp("cachesize", s)) {
+			ib.cachesize = atoi(eq);
+			return &ib;
+		}
+		if (!strcmp("maxkeypage", s)) {
+			ib.maxkeypage = atoi(eq);
+			return &ib;
+		}
+		if (!strcmp("minkeypage", s)) {
+			ib.minkeypage = atoi(eq);
+			return &ib;
+		}
+		if (!strcmp("lorder", s)) {
+			ib.lorder = atoi(eq);
+			return &ib;
+		}
+		if (!strcmp("psize", s)) {
+			ib.psize = atoi(eq);
+			return &ib;
+		}
+		break;
+	case DB_HASH:
+		if (!strcmp("bsize", s)) {
+			ih.bsize = atoi(eq);
+			return &ih;
+		}
+		if (!strcmp("ffactor", s)) {
+			ih.ffactor = atoi(eq);
+			return &ih;
+		}
+		if (!strcmp("nelem", s)) {
+			ih.nelem = atoi(eq);
+			return &ih;
+		}
+		if (!strcmp("cachesize", s)) {
+			ih.cachesize = atoi(eq);
+			return &ih;
+		}
+		if (!strcmp("lorder", s)) {
+			ih.lorder = atoi(eq);
+			return &ih;
+		}
+		break;
+	case DB_RECNO:
+		if (!strcmp("flags", s)) {
+			rh.flags = atoi(eq);
+			return &rh;
+		}
+		if (!strcmp("cachesize", s)) {
+			rh.cachesize = atoi(eq);
+			return &rh;
+		}
+		if (!strcmp("lorder", s)) {
+			rh.lorder = atoi(eq);
+			return &rh;
+		}
+		if (!strcmp("reclen", s)) {
+			rh.reclen = atoi(eq);
+			return &rh;
+		}
+		if (!strcmp("bval", s)) {
+			rh.bval = atoi(eq);
+			return &rh;
+		}
+		if (!strcmp("psize", s)) {
+			rh.psize = atoi(eq);
+			return &rh;
+		}
+		break;
+	}
+	errx(1, "%s: unknown structure value", s);
+	/* NOTREACHED */
+}
+
+static void *
+rfile(char *name, size_t *lenp)
+{
+	struct stat sb;
+	void *p;
+	int fd;
+	char *np;
+
+	for (; isspace((unsigned char)*name); ++name)
+		continue;
+	if ((np = strchr(name, '\n')) != NULL)
+		*np = '\0';
+	if ((fd = open(name, O_RDONLY, 0)) == -1 || fstat(fd, &sb) == -1)
+		err(1, "Cannot open `%s'", name);
+#ifdef NOT_PORTABLE
+	if (sb.st_size > (off_t)SIZE_T_MAX) {
+		errno = E2BIG;
+		err("Cannot process `%s'", name);
+	}
+#endif
+	if ((p = malloc((size_t)sb.st_size)) == NULL)
+		err(1, "Cannot allocate %zu bytes", (size_t)sb.st_size);
+	if (read(fd, p, (ssize_t)sb.st_size) != (ssize_t)sb.st_size)
+		err(1, "read failed");
+	*lenp = (size_t)sb.st_size;
+	(void)close(fd);
+	return p;
+}
+
+static void *
+xcopy(void *text, size_t len)
+{
+	void *p;
+
+	if ((p = malloc(len)) == NULL)
+		err(1, "Cannot allocate %zu bytes", len);
+	(void)memmove(p, text, len);
+	return p;
+}
+
+static void
+chkcmd(enum S state)
+{
+	if (state != COMMAND)
+		errx(1, "line %zu: not expecting command", lineno);
+}
+
+static void
+chkdata(enum S state)
+{
+	if (state != DATA)
+		errx(1, "line %zu: not expecting data", lineno);
+}
+
+static void
+chkkey(enum S state)
+{
+	if (state != KEY)
+		errx(1, "line %zu: not expecting a key", lineno);
+}
+
+static void
+usage(void)
+{
+	(void)fprintf(stderr,
+	    "Usage: %s [-l] [-f file] [-i info] [-o file] type script\n",
+	    getprogname());
+	exit(1);
+}
Index: src/tests/lib/libc/db/t_db.sh
diff -u /dev/null src/tests/lib/libc/db/t_db.sh:1.1
--- /dev/null	Fri Jan  7 15:05:58 2011
+++ src/tests/lib/libc/db/t_db.sh	Fri Jan  7 15:05:58 2011
@@ -0,0 +1,903 @@
+# $NetBSD: t_db.sh,v 1.1 2011/01/07 15:05:58 pgoyette Exp $
+#
+# Copyright (c) 2008 The NetBSD Foundation, Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+prog()
+{
+	echo $(atf_get_srcdir)/h_db
+}
+
+dict()
+{
+	if [ -f /usr/share/dict/words ]; then
+		echo /usr/share/dict/words
+	elif [ -f /usr/dict/words ]; then
+		echo /usr/dict/words
+	else
+		atf_fail "no dictionary found"
+	fi
+}
+
+SEVEN_SEVEN="abcdefg|abcdefg|abcdefg|abcdefg|abcdefg|abcdefg|abcdefg"
+
+atf_test_case small_btree
+small_btree_head()
+{
+	atf_set "descr" \
+		"Checks btree database using small keys and small data" \
+		"pairs: takes the first hundred entries in the dictionary," \
+		"and makes them be key/data pairs."
+}
+small_btree_body()
+{
+	TMPDIR="$(pwd)/db_dir"; export TMPDIR
+	mkdir ${TMPDIR}
+
+	sed 200q $(dict) >exp
+
+	for i in `sed 200q $(dict)`; do
+		echo p
+		echo k$i
+		echo d$i
+		echo g
+		echo k$i
+	done >in
+
+	atf_check -o file:exp "$(prog)" btree in
+}
+
+atf_test_case small_hash
+small_hash_head()
+{
+	atf_set "descr" \
+		"Checks hash database using small keys and small data" \
+		"pairs: takes the first hundred entries in the dictionary," \
+		"and makes them be key/data pairs."
+}
+small_hash_body()
+{
+	TMPDIR="$(pwd)/db_dir"; export TMPDIR
+	mkdir ${TMPDIR}
+
+	sed 200q $(dict) >exp
+
+	for i in `sed 200q $(dict)`; do
+		echo p
+		echo k$i
+		echo d$i
+		echo g
+		echo k$i
+	done >in
+
+	atf_check -o file:exp "$(prog)" hash in
+}
+
+atf_test_case small_recno
+small_recno_head()
+{
+	atf_set "descr" \
+		"Checks recno database using small keys and small data" \
+		"pairs: takes the first hundred entries in the dictionary," \
+		"and makes them be key/data pairs."
+}
+small_recno_body()
+{
+	TMPDIR="$(pwd)/db_dir"; export TMPDIR
+	mkdir ${TMPDIR}
+
+	sed 200q $(dict) >exp
+
+	sed 200q $(dict) |
+	awk '{ 
+		++i;
+		printf("p\nk%d\nd%s\ng\nk%d\n", i, $0, i);
+	}' >in
+
+	atf_check -o file:exp "$(prog)" recno in
+}
+
+atf_test_case medium_btree
+medium_btree_head()
+{
+	atf_set "descr" \
+		"Checks btree database using small keys and medium" \
+		"data pairs: takes the first 200 entries in the" \
+		"dictionary, and gives them each a medium size data entry."
+}
+medium_btree_body()
+{
+	TMPDIR="$(pwd)/db_dir"; export TMPDIR
+	mkdir ${TMPDIR}
+
+	mdata=abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz
+	echo $mdata |
+	awk '{ for (i = 1; i < 201; ++i) print $0 }' >exp
+
+	for i in $(sed 200q $(dict)); do
+		echo p
+		echo k$i
+		echo d$mdata
+		echo g
+		echo k$i
+	done >in
+
+	atf_check -o file:exp "$(prog)" btree in
+}
+
+atf_test_case medium_hash
+medium_hash_head()
+{
+	atf_set "descr" \
+		"Checks hash database using small keys and medium" \
+		"data pairs: takes the first 200 entries in the" \
+		"dictionary, and gives them each a medium size data entry."
+}
+medium_hash_body()
+{
+	TMPDIR="$(pwd)/db_dir"; export TMPDIR
+	mkdir ${TMPDIR}
+
+	mdata=abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz
+	echo $mdata |
+	awk '{ for (i = 1; i < 201; ++i) print $0 }' >exp
+
+	for i in $(sed 200q $(dict)); do
+		echo p
+		echo k$i
+		echo d$mdata
+		echo g
+		echo k$i
+	done >in
+
+	atf_check -o file:exp "$(prog)" hash in
+}
+
+atf_test_case medium_recno
+medium_recno_head()
+{
+	atf_set "descr" \
+		"Checks recno database using small keys and medium" \
+		"data pairs: takes the first 200 entries in the" \
+		"dictionary, and gives them each a medium size data entry."
+}
+medium_recno_body()
+{
+	TMPDIR="$(pwd)/db_dir"; export TMPDIR
+	mkdir ${TMPDIR}
+
+	mdata=abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz
+	echo $mdata |
+	awk '{ for (i = 1; i < 201; ++i) print $0 }' >exp
+
+	echo $mdata | 
+	awk '{  for (i = 1; i < 201; ++i)
+		printf("p\nk%d\nd%s\ng\nk%d\n", i, $0, i);
+	}' >in
+
+	atf_check -o file:exp "$(prog)" recno in
+}
+
+atf_test_case big_btree
+big_btree_head()
+{
+	atf_set "descr" \
+		"Checks btree database using small keys and big data" \
+		"pairs: inserts the programs in /bin with their paths" \
+		"as their keys."
+}
+big_btree_body()
+{
+	TMPDIR="$(pwd)/db_dir"; export TMPDIR
+	mkdir ${TMPDIR}
+
+	(find /bin -type f -print | xargs cat) >exp
+
+	for psize in 512 16384 65536; do
+		echo "checking page size: $psize"
+
+		for i in `find /bin -type f -print`; do
+			echo p
+			echo k$i
+			echo D$i
+			echo g
+			echo k$i
+		done >in
+
+		atf_check "$(prog)" -o out btree in
+		cmp -s exp out || atf_fail "test failed for page size: $psize"
+	done
+}
+
+atf_test_case big_hash
+big_hash_head()
+{
+	atf_set "descr" \
+		"Checks hash database using small keys and big data" \
+		"pairs: inserts the programs in /bin with their paths" \
+		"as their keys."
+}
+big_hash_body()
+{
+	TMPDIR="$(pwd)/db_dir"; export TMPDIR
+	mkdir ${TMPDIR}
+
+	(find /bin -type f -print | xargs cat) >exp
+
+	for i in `find /bin -type f -print`; do
+		echo p
+		echo k$i
+		echo D$i
+		echo g
+		echo k$i
+	done >in
+
+	atf_check "$(prog)" -o out hash in
+	cmp -s exp out || atf_fail "test failed"
+}
+
+atf_test_case big_recno
+big_recno_head()
+{
+	atf_set "descr" \
+		"Checks recno database using small keys and big data" \
+		"pairs: inserts the programs in /bin with their paths" \
+		"as their keys."
+}
+big_recno_body()
+{
+	TMPDIR="$(pwd)/db_dir"; export TMPDIR
+	mkdir ${TMPDIR}
+
+	(find /bin -type f -print | xargs cat) >exp
+
+	find /bin -type f -print | 
+	awk '{
+		++i;
+		printf("p\nk%d\nD%s\ng\nk%d\n", i, $0, i);
+	}' >in
+
+	for psize in 512 16384 65536; do
+		echo "checking page size: $psize"
+
+		atf_check "$(prog)" -o out recno in
+		cmp -s exp out || atf_fail "test failed for page size: $psize"
+	done
+}
+
+atf_test_case random_recno
+random_recno_head()
+{
+	atf_set "descr" "Checks recno database using random entries"
+}
+random_recno_body()
+{
+	TMPDIR="$(pwd)/db_dir"; export TMPDIR
+	mkdir ${TMPDIR}
+
+	echo $SEVEN_SEVEN |
+	awk '{
+		for (i = 37; i <= 37 + 88 * 17; i += 17) {
+			if (i % 41)
+				s = substr($0, 1, i % 41);
+			else
+				s = substr($0, 1);
+			printf("input key %d: %s\n", i, s);
+		}
+		for (i = 1; i <= 15; ++i) {
+			if (i % 41)
+				s = substr($0, 1, i % 41);
+			else
+				s = substr($0, 1);
+			printf("input key %d: %s\n", i, s);
+		}
+		for (i = 19234; i <= 19234 + 61 * 27; i += 27) {
+			if (i % 41)
+				s = substr($0, 1, i % 41);
+			else
+				s = substr($0, 1);
+			printf("input key %d: %s\n", i, s);
+		}
+		exit
+	}' >exp
+
+	cat exp |
+	awk 'BEGIN {
+			i = 37;
+			incr = 17;
+		}
+		{
+			printf("p\nk%d\nd%s\n", i, $0);
+			if (i == 19234 + 61 * 27)
+				exit;
+			if (i == 37 + 88 * 17) {
+				i = 1;
+				incr = 1;
+			} else if (i == 15) {
+				i = 19234;
+				incr = 27;
+			} else
+				i += incr;
+		}
+		END {
+			for (i = 37; i <= 37 + 88 * 17; i += 17)
+				printf("g\nk%d\n", i);
+			for (i = 1; i <= 15; ++i)
+				printf("g\nk%d\n", i);
+			for (i = 19234; i <= 19234 + 61 * 27; i += 27)
+				printf("g\nk%d\n", i);
+		}' >in
+
+	atf_check -o file:exp "$(prog)" recno in
+}
+
+atf_test_case reverse_recno
+reverse_recno_head()
+{
+	atf_set "descr" "Checks recno database using reverse order entries"
+}
+reverse_recno_body()
+{
+	TMPDIR="$(pwd)/db_dir"; export TMPDIR
+	mkdir ${TMPDIR}
+
+	echo $SEVEN_SEVEN |
+	awk ' {
+		for (i = 1500; i; --i) {
+			if (i % 34)
+				s = substr($0, 1, i % 34);
+			else
+				s = substr($0, 1);
+			printf("input key %d: %s\n", i, s);
+		}
+		exit;
+	}' >exp
+
+	cat exp |
+	awk 'BEGIN {
+			i = 1500;
+		}
+		{
+			printf("p\nk%d\nd%s\n", i, $0);
+			--i;
+		}
+		END {
+			for (i = 1500; i; --i) 
+				printf("g\nk%d\n", i);
+		}' >in
+
+	atf_check -o file:exp "$(prog)" recno in
+}
+		
+atf_test_case alternate_recno
+alternate_recno_head()
+{
+	atf_set "descr" "Checks recno database using alternating order entries"
+}
+alternate_recno_body()
+{
+	TMPDIR="$(pwd)/db_dir"; export TMPDIR
+	mkdir ${TMPDIR}
+
+	echo $SEVEN_SEVEN |
+	awk ' {
+		for (i = 1; i < 1200; i += 2) {
+			if (i % 34)
+				s = substr($0, 1, i % 34);
+			else
+				s = substr($0, 1);
+			printf("input key %d: %s\n", i, s);
+		}
+		for (i = 2; i < 1200; i += 2) {
+			if (i % 34)
+				s = substr($0, 1, i % 34);
+			else
+				s = substr($0, 1);
+			printf("input key %d: %s\n", i, s);
+		}
+		exit;
+	}' >exp
+
+	cat exp |
+	awk 'BEGIN {
+			i = 1;
+			even = 0;
+		}
+		{
+			printf("p\nk%d\nd%s\n", i, $0);
+			i += 2;
+			if (i >= 1200) {
+				if (even == 1)
+					exit;
+				even = 1;
+				i = 2;
+			}
+		}
+		END {
+			for (i = 1; i < 1200; ++i) 
+				printf("g\nk%d\n", i);
+		}' >in
+
+	atf_check "$(prog)" -o out recno in
+	
+	sort -o exp exp
+	sort -o out out
+
+	cmp -s exp out || atf_fail "test failed"
+}
+
+h_delete()
+{
+	TMPDIR="$(pwd)/db_dir"; export TMPDIR
+	mkdir ${TMPDIR}
+
+	type=$1
+
+	echo $SEVEN_SEVEN |
+	awk '{
+		for (i = 1; i <= 120; ++i)
+			printf("%05d: input key %d: %s\n", i, i, $0);
+		printf("%05d: input key %d: %s\n", 120, 120, $0);
+		printf("seq failed, no such key\n");
+		printf("%05d: input key %d: %s\n", 1, 1, $0);
+		printf("%05d: input key %d: %s\n", 2, 2, $0);
+		exit;
+	}' >exp
+
+	cat exp |
+	awk '{
+		if (i == 120)
+			exit;
+		printf("p\nk%d\nd%s\n", ++i, $0);
+	}
+	END {
+		printf("fR_NEXT\n");
+		for (i = 1; i <= 120; ++i)
+			printf("s\n");
+		printf("fR_CURSOR\ns\nk120\n");
+		printf("r\n");
+		printf("fR_NEXT\ns\n");
+		printf("fR_CURSOR\ns\nk1\n");
+		printf("r\n");
+		printf("fR_FIRST\ns\n");
+	}' >in
+
+	atf_check "$(prog)" -o out $type in
+	atf_check -o file:exp cat out
+}
+
+# FIXME: should it actually work? the original test apparently
+# was supposed to run such test, but didn't
+atf_test_case delete_btree
+delete_btree_head()
+{
+	atf_set "descr" "Checks removing records in btree database"
+}
+delete_btree_body()
+{
+#
+# The delete_btree test was skipped in the original ..../regress test
+# structure, so noone ever noticed that it didn't work!  Disable it for
+# now, until we correct the generation of in/out files to reflect the
+# actual collating sequence of key values ("19" comes before "2")
+#
+	atf_skip "delete_btreee test case is broken"
+	h_delete btree
+}
+
+atf_test_case delete_recno
+delete_recno_head()
+{
+	atf_set "descr" "Checks removing records in recno database"
+}
+delete_recno_body()
+{
+	h_delete recno
+}
+
+h_repeated()
+{
+	TMPDIR="$(pwd)/db_dir"; export TMPDIR
+	mkdir ${TMPDIR}
+
+	echo "" | 
+	awk 'BEGIN {
+		for (i = 1; i <= 10; ++i) {
+			printf("p\nkkey1\nD/bin/sh\n");
+			printf("p\nkkey2\nD/bin/csh\n");
+			if (i % 8 == 0) {
+				printf("c\nkkey2\nD/bin/csh\n");
+				printf("c\nkkey1\nD/bin/sh\n");
+				printf("e\t%d of 10 (comparison)\n", i);
+			} else
+				printf("e\t%d of 10             \n", i);
+			printf("r\nkkey1\nr\nkkey2\n");
+		}
+	}' >in
+
+	$(prog) btree in
+}
+
+atf_test_case repeated_btree
+repeated_btree_head()
+{
+	atf_set "descr" \
+		"Checks btree database with repeated small keys and" \
+		"big data pairs. Makes sure that overflow pages are reused"
+}
+repeated_btree_body()
+{
+	h_repeated btree
+}
+
+atf_test_case repeated_hash
+repeated_hash_head()
+{
+	atf_set "descr" \
+		"Checks hash database with repeated small keys and" \
+		"big data pairs. Makes sure that overflow pages are reused"
+}
+repeated_hash_body()
+{
+	h_repeated hash
+}
+
+atf_test_case duplicate_btree
+duplicate_btree_head()
+{
+	atf_set "descr" "Checks btree database with duplicate keys"
+}
+duplicate_btree_body()
+{
+	TMPDIR="$(pwd)/db_dir"; export TMPDIR
+	mkdir ${TMPDIR}
+
+	echo $SEVEN_SEVEN |
+	awk '{
+		for (i = 1; i <= 543; ++i)
+			printf("%05d: input key %d: %s\n", i, i, $0);
+		exit;
+	}' >exp
+
+	cat exp | 
+	awk '{
+		if (i++ % 2)
+			printf("p\nkduplicatekey\nd%s\n", $0);
+		else
+			printf("p\nkunique%dkey\nd%s\n", i, $0);
+	}
+	END {
+			printf("o\n");
+	}' >in
+
+	atf_check -o file:exp -x "$(prog) -iflags=1 btree in | sort"
+}
+
+h_cursor_flags()
+{
+	TMPDIR="$(pwd)/db_dir"; export TMPDIR
+	mkdir ${TMPDIR}
+
+	type=$1
+
+	echo $SEVEN_SEVEN |
+	awk '{
+		for (i = 1; i <= 20; ++i)
+			printf("%05d: input key %d: %s\n", i, i, $0);
+		exit;
+	}' >exp
+
+	# Test that R_CURSOR doesn't succeed before cursor initialized
+	cat exp |
+	awk '{
+		if (i == 10)
+			exit;
+		printf("p\nk%d\nd%s\n", ++i, $0);
+	}
+	END {
+		printf("fR_CURSOR\nr\n");
+		printf("eR_CURSOR SHOULD HAVE FAILED\n");
+	}' >in
+
+	atf_check -o ignore -e ignore -s ne:0 "$(prog)" -o out $type in
+	atf_check -s ne:0 test -s out
+
+	cat exp |
+	awk '{
+		if (i == 10)
+			exit;
+		printf("p\nk%d\nd%s\n", ++i, $0);
+	}
+	END {
+		printf("fR_CURSOR\np\nk1\ndsome data\n");
+		printf("eR_CURSOR SHOULD HAVE FAILED\n");
+	}' >in
+
+	atf_check -o ignore -e ignore -s ne:0 "$(prog)" -o out $type in
+	atf_check -s ne:0 test -s out
+}
+
+atf_test_case cursor_flags_btree
+cursor_flags_btree_head()
+{
+	atf_set "descr" \
+		"Checks use of cursor flags without initialization in btree database"
+}
+cursor_flags_btree_body()
+{
+	h_cursor_flags btree
+}
+
+atf_test_case cursor_flags_recno
+cursor_flags_recno_head()
+{
+	atf_set "descr" \
+		"Checks use of cursor flags without initialization in recno database"
+}
+cursor_flags_recno_body()
+{
+	h_cursor_flags recno
+}
+
+atf_test_case reverse_order_recno
+reverse_order_recno_head()
+{
+	atf_set "descr" "Checks reverse order inserts in recno database"
+}
+reverse_order_recno_body()
+{
+	TMPDIR="$(pwd)/db_dir"; export TMPDIR
+	mkdir ${TMPDIR}
+
+	echo $SEVEN_SEVEN |
+	awk '{
+		for (i = 1; i <= 779; ++i)
+			printf("%05d: input key %d: %s\n", i, i, $0);
+		exit;
+	}' >exp
+
+	cat exp |
+	awk '{
+		if (i == 0) {
+			i = 1;
+			printf("p\nk1\nd%s\n", $0);
+			printf("%s\n", "fR_IBEFORE");
+		} else
+			printf("p\nk1\nd%s\n", $0);
+	}
+	END {
+			printf("or\n");
+	}' >in
+
+	atf_check -o file:exp "$(prog)" recno in
+}
+
+atf_test_case small_page_btree
+small_page_btree_head()
+{
+	atf_set "descr" \
+		"Checks btree database with lots of keys and small page" \
+		"size: takes the first 20000 entries in the dictionary," \
+		"reverses them, and gives them each a small size data" \
+		"entry. Uses a small page size to make sure the btree" \
+		"split code gets hammered."
+}
+small_page_btree_body()
+{
+	TMPDIR="$(pwd)/db_dir"; export TMPDIR
+	mkdir ${TMPDIR}
+
+	mdata=abcdefghijklmnopqrstuvwxy
+	echo $mdata |
+	awk '{ for (i = 1; i < 20001; ++i) print $0 }' >exp
+
+	for i in `sed 20000q $(dict) | rev`; do
+		echo p
+		echo k$i
+		echo d$mdata
+		echo g
+		echo k$i
+	done >in
+
+	atf_check -o file:exp "$(prog)" -i psize=512 btree in
+}
+
+h_byte_orders()
+{
+	TMPDIR="$(pwd)/db_dir"; export TMPDIR
+	mkdir ${TMPDIR}
+
+	type=$1
+
+	sed 50q $(dict) >exp
+	for order in 1234 4321; do
+		for i in `sed 50q $(dict)`; do
+			echo p
+			echo k$i
+			echo d$i
+			echo g
+			echo k$i
+		done >in
+
+		atf_check -o file:exp "$(prog)" -ilorder=$order -f byte.file $type in
+
+		for i in `sed 50q $(dict)`; do
+			echo g
+			echo k$i
+		done >in
+
+		atf_check -o file:exp "$(prog)" -s -ilorder=$order -f byte.file $type in
+	done
+}
+
+atf_test_case byte_orders_btree
+byte_orders_btree_head()
+{
+	atf_set "descr" "Checks btree database using differing byte orders"
+}
+byte_orders_btree_body()
+{
+	h_byte_orders btree
+}
+
+atf_test_case byte_orders_hash
+byte_orders_hash_head()
+{
+	atf_set "descr" "Checks hash database using differing byte orders"
+}
+byte_orders_hash_body()
+{
+	h_byte_orders hash
+}
+
+h_bsize_ffactor()
+{
+	bsize=$1
+	ffactor=$2
+
+	echo "bucketsize $bsize, fill factor $ffactor"
+	atf_check -o file:exp "$(prog)" "-ibsize=$bsize,\
+ffactor=$ffactor,nelem=25000,cachesize=65536" hash in
+}
+
+atf_test_case bsize_ffactor
+bsize_ffactor_head()
+{
+	atf_set "descr" "Checks hash database with various" \
+					"bucketsizes and fill factors"
+}
+bsize_ffactor_body()
+{
+	TMPDIR="$(pwd)/db_dir"; export TMPDIR
+	mkdir ${TMPDIR}
+
+	echo $SEVEN_SEVEN |
+	awk '{
+		for (i = 1; i <= 10000; ++i) {
+			if (i % 34)
+				s = substr($0, 1, i % 34);
+			else
+				s = substr($0, 1);
+			printf("%s\n", s);
+		}
+		exit;
+
+	}' >exp
+
+	sed 10000q $(dict) |
+	awk 'BEGIN {
+		ds="'$SEVEN_SEVEN'"
+	}
+	{
+		if (++i % 34)
+			s = substr(ds, 1, i % 34);
+		else
+			s = substr(ds, 1);
+		printf("p\nk%s\nd%s\n", $0, s);
+	}' >in
+
+	sed 10000q $(dict) |
+	awk '{
+		++i;
+		printf("g\nk%s\n", $0);
+	}' >>in
+
+	h_bsize_ffactor 256 11
+	h_bsize_ffactor 256 14
+	h_bsize_ffactor 256 21
+
+	h_bsize_ffactor 512 21
+	h_bsize_ffactor 512 28
+	h_bsize_ffactor 512 43
+
+	h_bsize_ffactor 1024 43
+	h_bsize_ffactor 1024 57
+	h_bsize_ffactor 1024 85
+
+	h_bsize_ffactor 2048 85
+	h_bsize_ffactor 2048 114
+	h_bsize_ffactor 2048 171
+
+	h_bsize_ffactor 4096 171
+	h_bsize_ffactor 4096 228
+	h_bsize_ffactor 4096 341
+
+	h_bsize_ffactor 8192 341
+	h_bsize_ffactor 8192 455
+	h_bsize_ffactor 8192 683
+}
+
+# FIXME: what does it test?
+atf_test_case four_char_hash
+four_char_hash_head()
+{
+	atf_set "descr" \
+		"Checks hash database with 4 char key and" \
+		"value insert on a 65536 bucket size"
+}
+four_char_hash_body()
+{
+	TMPDIR="$(pwd)/db_dir"; export TMPDIR
+	mkdir ${TMPDIR}
+
+	cat >in <<EOF
+p
+k1234
+d1234
+r
+k1234
+EOF
+
+	atf_check "$(prog)" -i bsize=65536 hash in
+}
+
+atf_init_test_cases()
+{
+	atf_add_test_case small_btree
+	atf_add_test_case small_hash
+	atf_add_test_case small_recno
+	atf_add_test_case medium_btree
+	atf_add_test_case medium_hash
+	atf_add_test_case medium_recno
+	atf_add_test_case big_btree
+	atf_add_test_case big_hash
+	atf_add_test_case big_recno
+	atf_add_test_case random_recno
+	atf_add_test_case reverse_recno
+	atf_add_test_case alternate_recno
+	atf_add_test_case delete_btree
+	atf_add_test_case delete_recno
+	atf_add_test_case repeated_btree
+	atf_add_test_case repeated_hash
+	atf_add_test_case duplicate_btree
+	atf_add_test_case cursor_flags_btree
+	atf_add_test_case cursor_flags_recno
+	atf_add_test_case reverse_order_recno
+	atf_add_test_case small_page_btree
+	atf_add_test_case byte_orders_btree
+	atf_add_test_case byte_orders_hash
+	atf_add_test_case bsize_ffactor
+	atf_add_test_case four_char_hash
+}

Reply via email to