11573Srgrimes/*-
214287Spst * Copyright (c) 1992, 1993, 1994
31573Srgrimes *	The Regents of the University of California.  All rights reserved.
41573Srgrimes *
51573Srgrimes * Redistribution and use in source and binary forms, with or without
61573Srgrimes * modification, are permitted provided that the following conditions
71573Srgrimes * are met:
81573Srgrimes * 1. Redistributions of source code must retain the above copyright
91573Srgrimes *    notice, this list of conditions and the following disclaimer.
101573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111573Srgrimes *    notice, this list of conditions and the following disclaimer in the
121573Srgrimes *    documentation and/or other materials provided with the distribution.
131573Srgrimes * 4. Neither the name of the University nor the names of its contributors
141573Srgrimes *    may be used to endorse or promote products derived from this software
151573Srgrimes *    without specific prior written permission.
161573Srgrimes *
171573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201573Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271573Srgrimes * SUCH DAMAGE.
281573Srgrimes */
291573Srgrimes
301573Srgrimes#ifndef lint
311573Srgrimesstatic char copyright[] =
3214287Spst"@(#) Copyright (c) 1992, 1993, 1994\n\
331573Srgrimes	The Regents of the University of California.  All rights reserved.\n";
341573Srgrimes#endif /* not lint */
351573Srgrimes
3692986Sobrien#if defined(LIBC_SCCS) && !defined(lint)
3714287Spststatic char sccsid[] = "@(#)dbtest.c	8.17 (Berkeley) 9/1/94";
3892986Sobrien#endif /* LIBC_SCCS and not lint */
3992986Sobrien#include <sys/cdefs.h>
4092986Sobrien__FBSDID("$FreeBSD$");
411573Srgrimes
421573Srgrimes#include <sys/param.h>
431573Srgrimes#include <sys/stat.h>
441573Srgrimes
451573Srgrimes#include <ctype.h>
461573Srgrimes#include <errno.h>
471573Srgrimes#include <fcntl.h>
481573Srgrimes#include <limits.h>
491573Srgrimes#include <stdio.h>
501573Srgrimes#include <stdlib.h>
511573Srgrimes#include <string.h>
521573Srgrimes#include <unistd.h>
531573Srgrimes
541573Srgrimes#include <db.h>
551573Srgrimes
561573Srgrimesenum S { COMMAND, COMPARE, GET, PUT, REMOVE, SEQ, SEQFLAG, KEY, DATA };
571573Srgrimes
5892905Sobrienvoid	 compare(DBT *, DBT *);
5992905SobrienDBTYPE	 dbtype(char *);
6092905Sobrienvoid	 dump(DB *, int);
6192941Sobrienvoid	 err(const char *, ...) __printflike(1, 2);
6292905Sobrienvoid	 get(DB *, DBT *);
6392905Sobrienvoid	 getdata(DB *, DBT *, DBT *);
6492905Sobrienvoid	 put(DB *, DBT *, DBT *);
6592905Sobrienvoid	 rem(DB *, DBT *);
6692905Sobrienchar	*sflags(int);
6792905Sobrienvoid	 synk(DB *);
6892905Sobrienvoid	*rfile(char *, size_t *);
6992905Sobrienvoid	 seq(DB *, DBT *);
7092905Sobrienu_int	 setflags(char *);
7192905Sobrienvoid	*setinfo(DBTYPE, char *);
7292905Sobrienvoid	 usage(void);
7392905Sobrienvoid	*xmalloc(char *, size_t);
741573Srgrimes
7514287SpstDBTYPE type;				/* Database type. */
7614287Spstvoid *infop;				/* Iflags. */
7714287Spstu_long lineno;				/* Current line in test script. */
7814287Spstu_int flags;				/* Current DB flags. */
7914287Spstint ofd = STDOUT_FILENO;		/* Standard output fd. */
801573Srgrimes
811573SrgrimesDB *XXdbp;				/* Global for gdb. */
8214287Spstint XXlineno;				/* Fast breakpoint for gdb. */
831573Srgrimes
841573Srgrimesint
851573Srgrimesmain(argc, argv)
861573Srgrimes	int argc;
871573Srgrimes	char *argv[];
881573Srgrimes{
891573Srgrimes	extern int optind;
901573Srgrimes	extern char *optarg;
911573Srgrimes	enum S command, state;
921573Srgrimes	DB *dbp;
931573Srgrimes	DBT data, key, keydata;
941573Srgrimes	size_t len;
9514287Spst	int ch, oflags, sflag;
9614287Spst	char *fname, *infoarg, *p, *t, buf[8 * 1024];
971573Srgrimes
981573Srgrimes	infoarg = NULL;
991573Srgrimes	fname = NULL;
1001573Srgrimes	oflags = O_CREAT | O_RDWR;
10114287Spst	sflag = 0;
102176380Skevlo	while ((ch = getopt(argc, argv, "f:i:lo:s")) != -1)
10314287Spst		switch (ch) {
1041573Srgrimes		case 'f':
1051573Srgrimes			fname = optarg;
1061573Srgrimes			break;
1071573Srgrimes		case 'i':
1081573Srgrimes			infoarg = optarg;
1091573Srgrimes			break;
1101573Srgrimes		case 'l':
1111573Srgrimes			oflags |= DB_LOCK;
1121573Srgrimes			break;
1131573Srgrimes		case 'o':
1141573Srgrimes			if ((ofd = open(optarg,
1151573Srgrimes			    O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
1161573Srgrimes				err("%s: %s", optarg, strerror(errno));
1171573Srgrimes			break;
11814287Spst		case 's':
11914287Spst			sflag = 1;
12014287Spst			break;
1211573Srgrimes		case '?':
1221573Srgrimes		default:
1231573Srgrimes			usage();
1241573Srgrimes		}
1251573Srgrimes	argc -= optind;
1261573Srgrimes	argv += optind;
1271573Srgrimes
1281573Srgrimes	if (argc != 2)
1291573Srgrimes		usage();
1301573Srgrimes
1311573Srgrimes	/* Set the type. */
1321573Srgrimes	type = dbtype(*argv++);
1331573Srgrimes
1341573Srgrimes	/* Open the descriptor file. */
13514287Spst        if (strcmp(*argv, "-") && freopen(*argv, "r", stdin) == NULL)
13614287Spst	    err("%s: %s", *argv, strerror(errno));
1371573Srgrimes
1381573Srgrimes	/* Set up the db structure as necessary. */
1391573Srgrimes	if (infoarg == NULL)
1401573Srgrimes		infop = NULL;
1411573Srgrimes	else
1421573Srgrimes		for (p = strtok(infoarg, ",\t "); p != NULL;
1431573Srgrimes		    p = strtok(0, ",\t "))
1441573Srgrimes			if (*p != '\0')
1451573Srgrimes				infop = setinfo(type, p);
1461573Srgrimes
14714287Spst	/*
14814287Spst	 * Open the DB.  Delete any preexisting copy, you almost never
14914287Spst	 * want it around, and it often screws up tests.
15014287Spst	 */
1511573Srgrimes	if (fname == NULL) {
1521573Srgrimes		p = getenv("TMPDIR");
1531573Srgrimes		if (p == NULL)
1541573Srgrimes			p = "/var/tmp";
15564239Skris		(void)snprintf(buf, sizeof(buf), "%s/__dbtest", p);
1561573Srgrimes		fname = buf;
1571573Srgrimes		(void)unlink(buf);
15814287Spst	} else  if (!sflag)
15914287Spst		(void)unlink(fname);
16014287Spst
1611573Srgrimes	if ((dbp = dbopen(fname,
1621573Srgrimes	    oflags, S_IRUSR | S_IWUSR, type, infop)) == NULL)
1631573Srgrimes		err("dbopen: %s", strerror(errno));
1641573Srgrimes	XXdbp = dbp;
1651573Srgrimes
1661573Srgrimes	state = COMMAND;
1671573Srgrimes	for (lineno = 1;
1681573Srgrimes	    (p = fgets(buf, sizeof(buf), stdin)) != NULL; ++lineno) {
16914287Spst		/* Delete the newline, displaying the key/data is easier. */
17014287Spst		if (ofd == STDOUT_FILENO && (t = strchr(p, '\n')) != NULL)
17114287Spst			*t = '\0';
17214287Spst		if ((len = strlen(buf)) == 0 || isspace(*p) || *p == '#')
17314287Spst			continue;
17414287Spst
17514287Spst		/* Convenient gdb break point. */
17614287Spst		if (XXlineno == lineno)
17714287Spst			XXlineno = 1;
17814287Spst		switch (*p) {
1791573Srgrimes		case 'c':			/* compare */
1801573Srgrimes			if (state != COMMAND)
1811573Srgrimes				err("line %lu: not expecting command", lineno);
1821573Srgrimes			state = KEY;
1831573Srgrimes			command = COMPARE;
1841573Srgrimes			break;
1851573Srgrimes		case 'e':			/* echo */
1861573Srgrimes			if (state != COMMAND)
1871573Srgrimes				err("line %lu: not expecting command", lineno);
1881573Srgrimes			/* Don't display the newline, if CR at EOL. */
1891573Srgrimes			if (p[len - 2] == '\r')
1901573Srgrimes				--len;
19114287Spst			if (write(ofd, p + 1, len - 1) != len - 1 ||
19214287Spst			    write(ofd, "\n", 1) != 1)
1931573Srgrimes				err("write: %s", strerror(errno));
1941573Srgrimes			break;
1951573Srgrimes		case 'g':			/* get */
1961573Srgrimes			if (state != COMMAND)
1971573Srgrimes				err("line %lu: not expecting command", lineno);
1981573Srgrimes			state = KEY;
1991573Srgrimes			command = GET;
2001573Srgrimes			break;
2011573Srgrimes		case 'p':			/* put */
2021573Srgrimes			if (state != COMMAND)
2031573Srgrimes				err("line %lu: not expecting command", lineno);
2041573Srgrimes			state = KEY;
2051573Srgrimes			command = PUT;
2061573Srgrimes			break;
2071573Srgrimes		case 'r':			/* remove */
2081573Srgrimes			if (state != COMMAND)
2091573Srgrimes				err("line %lu: not expecting command", lineno);
21014287Spst                        if (flags == R_CURSOR) {
21114287Spst				rem(dbp, &key);
21214287Spst				state = COMMAND;
21314287Spst                        } else {
21414287Spst				state = KEY;
21514287Spst				command = REMOVE;
21614287Spst			}
2171573Srgrimes			break;
21814287Spst		case 'S':			/* sync */
21914287Spst			if (state != COMMAND)
22014287Spst				err("line %lu: not expecting command", lineno);
22114287Spst			synk(dbp);
22214287Spst			state = COMMAND;
22314287Spst			break;
2241573Srgrimes		case 's':			/* seq */
2251573Srgrimes			if (state != COMMAND)
2261573Srgrimes				err("line %lu: not expecting command", lineno);
2271573Srgrimes			if (flags == R_CURSOR) {
2281573Srgrimes				state = KEY;
2291573Srgrimes				command = SEQ;
2301573Srgrimes			} else
2311573Srgrimes				seq(dbp, &key);
2321573Srgrimes			break;
2331573Srgrimes		case 'f':
2341573Srgrimes			flags = setflags(p + 1);
2351573Srgrimes			break;
2361573Srgrimes		case 'D':			/* data file */
2371573Srgrimes			if (state != DATA)
2381573Srgrimes				err("line %lu: not expecting data", lineno);
2391573Srgrimes			data.data = rfile(p + 1, &data.size);
2401573Srgrimes			goto ldata;
2411573Srgrimes		case 'd':			/* data */
2421573Srgrimes			if (state != DATA)
2431573Srgrimes				err("line %lu: not expecting data", lineno);
2441573Srgrimes			data.data = xmalloc(p + 1, len - 1);
2451573Srgrimes			data.size = len - 1;
24614287Spstldata:			switch (command) {
2471573Srgrimes			case COMPARE:
2481573Srgrimes				compare(&keydata, &data);
2491573Srgrimes				break;
2501573Srgrimes			case PUT:
2511573Srgrimes				put(dbp, &key, &data);
2521573Srgrimes				break;
2531573Srgrimes			default:
2541573Srgrimes				err("line %lu: command doesn't take data",
2551573Srgrimes				    lineno);
2561573Srgrimes			}
2571573Srgrimes			if (type != DB_RECNO)
2581573Srgrimes				free(key.data);
2591573Srgrimes			free(data.data);
2601573Srgrimes			state = COMMAND;
2611573Srgrimes			break;
2621573Srgrimes		case 'K':			/* key file */
2631573Srgrimes			if (state != KEY)
2641573Srgrimes				err("line %lu: not expecting a key", lineno);
2651573Srgrimes			if (type == DB_RECNO)
2661573Srgrimes				err("line %lu: 'K' not available for recno",
2671573Srgrimes				    lineno);
2681573Srgrimes			key.data = rfile(p + 1, &key.size);
2691573Srgrimes			goto lkey;
2701573Srgrimes		case 'k':			/* key */
2711573Srgrimes			if (state != KEY)
2721573Srgrimes				err("line %lu: not expecting a key", lineno);
2731573Srgrimes			if (type == DB_RECNO) {
2741573Srgrimes				static recno_t recno;
2751573Srgrimes				recno = atoi(p + 1);
2761573Srgrimes				key.data = &recno;
2771573Srgrimes				key.size = sizeof(recno);
2781573Srgrimes			} else {
2791573Srgrimes				key.data = xmalloc(p + 1, len - 1);
2801573Srgrimes				key.size = len - 1;
2811573Srgrimes			}
28214287Spstlkey:			switch (command) {
2831573Srgrimes			case COMPARE:
2841573Srgrimes				getdata(dbp, &key, &keydata);
2851573Srgrimes				state = DATA;
2861573Srgrimes				break;
2871573Srgrimes			case GET:
2881573Srgrimes				get(dbp, &key);
2891573Srgrimes				if (type != DB_RECNO)
2901573Srgrimes					free(key.data);
2911573Srgrimes				state = COMMAND;
2921573Srgrimes				break;
2931573Srgrimes			case PUT:
2941573Srgrimes				state = DATA;
2951573Srgrimes				break;
2961573Srgrimes			case REMOVE:
2971573Srgrimes				rem(dbp, &key);
29814287Spst				if ((type != DB_RECNO) && (flags != R_CURSOR))
2991573Srgrimes					free(key.data);
3001573Srgrimes				state = COMMAND;
3011573Srgrimes				break;
3021573Srgrimes			case SEQ:
3031573Srgrimes				seq(dbp, &key);
30414287Spst				if ((type != DB_RECNO) && (flags != R_CURSOR))
3051573Srgrimes					free(key.data);
3061573Srgrimes				state = COMMAND;
3071573Srgrimes				break;
3081573Srgrimes			default:
3091573Srgrimes				err("line %lu: command doesn't take a key",
3101573Srgrimes				    lineno);
3111573Srgrimes			}
3121573Srgrimes			break;
3131573Srgrimes		case 'o':
3141573Srgrimes			dump(dbp, p[1] == 'r');
3151573Srgrimes			break;
3161573Srgrimes		default:
3171573Srgrimes			err("line %lu: %s: unknown command character",
31814287Spst			    lineno, p);
3191573Srgrimes		}
3201573Srgrimes	}
3211573Srgrimes#ifdef STATISTICS
32214287Spst	/*
32314287Spst	 * -l must be used (DB_LOCK must be set) for this to be
32414287Spst	 * used, otherwise a page will be locked and it will fail.
32514287Spst	 */
32614287Spst	if (type == DB_BTREE && oflags & DB_LOCK)
3271573Srgrimes		__bt_stat(dbp);
3281573Srgrimes#endif
3291573Srgrimes	if (dbp->close(dbp))
3301573Srgrimes		err("db->close: %s", strerror(errno));
3311573Srgrimes	(void)close(ofd);
3321573Srgrimes	exit(0);
3331573Srgrimes}
3341573Srgrimes
3351573Srgrimes#define	NOOVERWRITE	"put failed, would overwrite key\n"
3361573Srgrimes
3371573Srgrimesvoid
3381573Srgrimescompare(db1, db2)
3391573Srgrimes	DBT *db1, *db2;
3401573Srgrimes{
34192889Sobrien	size_t len;
34292889Sobrien	u_char *p1, *p2;
3431573Srgrimes
3441573Srgrimes	if (db1->size != db2->size)
3451573Srgrimes		printf("compare failed: key->data len %lu != data len %lu\n",
3461573Srgrimes		    db1->size, db2->size);
3471573Srgrimes
3481573Srgrimes	len = MIN(db1->size, db2->size);
3491573Srgrimes	for (p1 = db1->data, p2 = db2->data; len--;)
3501573Srgrimes		if (*p1++ != *p2++) {
3511573Srgrimes			printf("compare failed at offset %d\n",
3521573Srgrimes			    p1 - (u_char *)db1->data);
3531573Srgrimes			break;
3541573Srgrimes		}
3551573Srgrimes}
3561573Srgrimes
3571573Srgrimesvoid
3581573Srgrimesget(dbp, kp)
3591573Srgrimes	DB *dbp;
3601573Srgrimes	DBT *kp;
3611573Srgrimes{
3621573Srgrimes	DBT data;
3631573Srgrimes
36414287Spst	switch (dbp->get(dbp, kp, &data, flags)) {
3651573Srgrimes	case 0:
3661573Srgrimes		(void)write(ofd, data.data, data.size);
36714287Spst		if (ofd == STDOUT_FILENO)
36814287Spst			(void)write(ofd, "\n", 1);
3691573Srgrimes		break;
3701573Srgrimes	case -1:
3711573Srgrimes		err("line %lu: get: %s", lineno, strerror(errno));
3721573Srgrimes		/* NOTREACHED */
3731573Srgrimes	case 1:
37414287Spst#define	NOSUCHKEY	"get failed, no such key\n"
37514287Spst		if (ofd != STDOUT_FILENO)
37614287Spst			(void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1);
37714287Spst		else
37814287Spst			(void)fprintf(stderr, "%d: %.*s: %s",
37914287Spst			    lineno, MIN(kp->size, 20), kp->data, NOSUCHKEY);
38014287Spst#undef	NOSUCHKEY
3811573Srgrimes		break;
3821573Srgrimes	}
3831573Srgrimes}
3841573Srgrimes
3851573Srgrimesvoid
3861573Srgrimesgetdata(dbp, kp, dp)
3871573Srgrimes	DB *dbp;
3881573Srgrimes	DBT *kp, *dp;
3891573Srgrimes{
39014287Spst	switch (dbp->get(dbp, kp, dp, flags)) {
3911573Srgrimes	case 0:
3921573Srgrimes		return;
3931573Srgrimes	case -1:
3941573Srgrimes		err("line %lu: getdata: %s", lineno, strerror(errno));
3951573Srgrimes		/* NOTREACHED */
3961573Srgrimes	case 1:
39714287Spst		err("line %lu: getdata failed, no such key", lineno);
3981573Srgrimes		/* NOTREACHED */
3991573Srgrimes	}
4001573Srgrimes}
4011573Srgrimes
4021573Srgrimesvoid
4031573Srgrimesput(dbp, kp, dp)
4041573Srgrimes	DB *dbp;
4051573Srgrimes	DBT *kp, *dp;
4061573Srgrimes{
40714287Spst	switch (dbp->put(dbp, kp, dp, flags)) {
4081573Srgrimes	case 0:
4091573Srgrimes		break;
4101573Srgrimes	case -1:
4111573Srgrimes		err("line %lu: put: %s", lineno, strerror(errno));
4121573Srgrimes		/* NOTREACHED */
4131573Srgrimes	case 1:
4141573Srgrimes		(void)write(ofd, NOOVERWRITE, sizeof(NOOVERWRITE) - 1);
4151573Srgrimes		break;
4161573Srgrimes	}
4171573Srgrimes}
4181573Srgrimes
4191573Srgrimesvoid
4201573Srgrimesrem(dbp, kp)
4211573Srgrimes	DB *dbp;
4221573Srgrimes	DBT *kp;
4231573Srgrimes{
42414287Spst	switch (dbp->del(dbp, kp, flags)) {
4251573Srgrimes	case 0:
4261573Srgrimes		break;
4271573Srgrimes	case -1:
42814287Spst		err("line %lu: rem: %s", lineno, strerror(errno));
4291573Srgrimes		/* NOTREACHED */
4301573Srgrimes	case 1:
43114287Spst#define	NOSUCHKEY	"rem failed, no such key\n"
43214287Spst		if (ofd != STDOUT_FILENO)
43314287Spst			(void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1);
43414287Spst		else if (flags != R_CURSOR)
43514287Spst			(void)fprintf(stderr, "%d: %.*s: %s",
43614287Spst			    lineno, MIN(kp->size, 20), kp->data, NOSUCHKEY);
43714287Spst		else
43814287Spst			(void)fprintf(stderr,
43914287Spst			    "%d: rem of cursor failed\n", lineno);
44014287Spst#undef	NOSUCHKEY
4411573Srgrimes		break;
4421573Srgrimes	}
4431573Srgrimes}
4441573Srgrimes
4451573Srgrimesvoid
44614287Spstsynk(dbp)
44714287Spst	DB *dbp;
44814287Spst{
44914287Spst	switch (dbp->sync(dbp, flags)) {
45014287Spst	case 0:
45114287Spst		break;
45214287Spst	case -1:
45314287Spst		err("line %lu: synk: %s", lineno, strerror(errno));
45414287Spst		/* NOTREACHED */
45514287Spst	}
45614287Spst}
45714287Spst
45814287Spstvoid
4591573Srgrimesseq(dbp, kp)
4601573Srgrimes	DB *dbp;
4611573Srgrimes	DBT *kp;
4621573Srgrimes{
4631573Srgrimes	DBT data;
4641573Srgrimes
46514287Spst	switch (dbp->seq(dbp, kp, &data, flags)) {
4661573Srgrimes	case 0:
4671573Srgrimes		(void)write(ofd, data.data, data.size);
46814287Spst		if (ofd == STDOUT_FILENO)
46914287Spst			(void)write(ofd, "\n", 1);
4701573Srgrimes		break;
4711573Srgrimes	case -1:
4721573Srgrimes		err("line %lu: seq: %s", lineno, strerror(errno));
4731573Srgrimes		/* NOTREACHED */
4741573Srgrimes	case 1:
47514287Spst#define	NOSUCHKEY	"seq failed, no such key\n"
47614287Spst		if (ofd != STDOUT_FILENO)
47714287Spst			(void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1);
47814287Spst		else if (flags == R_CURSOR)
47914287Spst			(void)fprintf(stderr, "%d: %.*s: %s",
48014287Spst			    lineno, MIN(kp->size, 20), kp->data, NOSUCHKEY);
48114287Spst		else
48214287Spst			(void)fprintf(stderr,
48314287Spst			    "%d: seq (%s) failed\n", lineno, sflags(flags));
48414287Spst#undef	NOSUCHKEY
4851573Srgrimes		break;
4861573Srgrimes	}
4871573Srgrimes}
4881573Srgrimes
4891573Srgrimesvoid
4901573Srgrimesdump(dbp, rev)
4911573Srgrimes	DB *dbp;
4921573Srgrimes	int rev;
4931573Srgrimes{
4941573Srgrimes	DBT key, data;
4951573Srgrimes	int flags, nflags;
4961573Srgrimes
4971573Srgrimes	if (rev) {
4981573Srgrimes		flags = R_LAST;
4991573Srgrimes		nflags = R_PREV;
5001573Srgrimes	} else {
5011573Srgrimes		flags = R_FIRST;
5021573Srgrimes		nflags = R_NEXT;
5031573Srgrimes	}
5041573Srgrimes	for (;; flags = nflags)
50514287Spst		switch (dbp->seq(dbp, &key, &data, flags)) {
5061573Srgrimes		case 0:
5071573Srgrimes			(void)write(ofd, data.data, data.size);
50814287Spst			if (ofd == STDOUT_FILENO)
50914287Spst				(void)write(ofd, "\n", 1);
5101573Srgrimes			break;
5111573Srgrimes		case 1:
5121573Srgrimes			goto done;
5131573Srgrimes		case -1:
5141573Srgrimes			err("line %lu: (dump) seq: %s",
5151573Srgrimes			    lineno, strerror(errno));
5161573Srgrimes			/* NOTREACHED */
5171573Srgrimes		}
5181573Srgrimesdone:	return;
5191573Srgrimes}
52014287Spst
5211573Srgrimesu_int
5221573Srgrimessetflags(s)
5231573Srgrimes	char *s;
5241573Srgrimes{
5251573Srgrimes	char *p, *index();
5261573Srgrimes
5271573Srgrimes	for (; isspace(*s); ++s);
52814287Spst	if (*s == '\n' || *s == '\0')
5291573Srgrimes		return (0);
5301573Srgrimes	if ((p = index(s, '\n')) != NULL)
5311573Srgrimes		*p = '\0';
53214287Spst	if (!strcmp(s, "R_CURSOR"))		return (R_CURSOR);
53314287Spst	if (!strcmp(s, "R_FIRST"))		return (R_FIRST);
53414287Spst	if (!strcmp(s, "R_IAFTER")) 		return (R_IAFTER);
53514287Spst	if (!strcmp(s, "R_IBEFORE")) 		return (R_IBEFORE);
53614287Spst	if (!strcmp(s, "R_LAST")) 		return (R_LAST);
53714287Spst	if (!strcmp(s, "R_NEXT")) 		return (R_NEXT);
53814287Spst	if (!strcmp(s, "R_NOOVERWRITE"))	return (R_NOOVERWRITE);
53914287Spst	if (!strcmp(s, "R_PREV"))		return (R_PREV);
54014287Spst	if (!strcmp(s, "R_SETCURSOR"))		return (R_SETCURSOR);
54114287Spst
5421573Srgrimes	err("line %lu: %s: unknown flag", lineno, s);
5431573Srgrimes	/* NOTREACHED */
5441573Srgrimes}
5458870Srgrimes
54614287Spstchar *
54714287Spstsflags(flags)
54814287Spst	int flags;
54914287Spst{
55014287Spst	switch (flags) {
55114287Spst	case R_CURSOR:		return ("R_CURSOR");
55214287Spst	case R_FIRST:		return ("R_FIRST");
55314287Spst	case R_IAFTER:		return ("R_IAFTER");
55414287Spst	case R_IBEFORE:		return ("R_IBEFORE");
55514287Spst	case R_LAST:		return ("R_LAST");
55614287Spst	case R_NEXT:		return ("R_NEXT");
55714287Spst	case R_NOOVERWRITE:	return ("R_NOOVERWRITE");
55814287Spst	case R_PREV:		return ("R_PREV");
55914287Spst	case R_SETCURSOR:	return ("R_SETCURSOR");
56014287Spst	}
56114287Spst
56214287Spst	return ("UNKNOWN!");
56314287Spst}
56414287Spst
5651573SrgrimesDBTYPE
5661573Srgrimesdbtype(s)
5671573Srgrimes	char *s;
5681573Srgrimes{
5691573Srgrimes	if (!strcmp(s, "btree"))
5701573Srgrimes		return (DB_BTREE);
5711573Srgrimes	if (!strcmp(s, "hash"))
5721573Srgrimes		return (DB_HASH);
5731573Srgrimes	if (!strcmp(s, "recno"))
5741573Srgrimes		return (DB_RECNO);
5751573Srgrimes	err("%s: unknown type (use btree, hash or recno)", s);
5761573Srgrimes	/* NOTREACHED */
5771573Srgrimes}
5781573Srgrimes
5791573Srgrimesvoid *
5801573Srgrimessetinfo(type, s)
5811573Srgrimes	DBTYPE type;
5821573Srgrimes	char *s;
5831573Srgrimes{
5841573Srgrimes	static BTREEINFO ib;
5851573Srgrimes	static HASHINFO ih;
5861573Srgrimes	static RECNOINFO rh;
5871573Srgrimes	char *eq, *index();
5881573Srgrimes
5891573Srgrimes	if ((eq = index(s, '=')) == NULL)
5901573Srgrimes		err("%s: illegal structure set statement", s);
5911573Srgrimes	*eq++ = '\0';
5921573Srgrimes	if (!isdigit(*eq))
5931573Srgrimes		err("%s: structure set statement must be a number", s);
59414287Spst
59514287Spst	switch (type) {
5961573Srgrimes	case DB_BTREE:
5971573Srgrimes		if (!strcmp("flags", s)) {
5981573Srgrimes			ib.flags = atoi(eq);
5991573Srgrimes			return (&ib);
6001573Srgrimes		}
6011573Srgrimes		if (!strcmp("cachesize", s)) {
6021573Srgrimes			ib.cachesize = atoi(eq);
6031573Srgrimes			return (&ib);
6041573Srgrimes		}
6051573Srgrimes		if (!strcmp("maxkeypage", s)) {
6061573Srgrimes			ib.maxkeypage = atoi(eq);
6071573Srgrimes			return (&ib);
6081573Srgrimes		}
6091573Srgrimes		if (!strcmp("minkeypage", s)) {
6101573Srgrimes			ib.minkeypage = atoi(eq);
6111573Srgrimes			return (&ib);
6121573Srgrimes		}
6131573Srgrimes		if (!strcmp("lorder", s)) {
6141573Srgrimes			ib.lorder = atoi(eq);
6151573Srgrimes			return (&ib);
6161573Srgrimes		}
6171573Srgrimes		if (!strcmp("psize", s)) {
6181573Srgrimes			ib.psize = atoi(eq);
6191573Srgrimes			return (&ib);
6201573Srgrimes		}
6211573Srgrimes		break;
6221573Srgrimes	case DB_HASH:
6231573Srgrimes		if (!strcmp("bsize", s)) {
6241573Srgrimes			ih.bsize = atoi(eq);
6251573Srgrimes			return (&ih);
6261573Srgrimes		}
6271573Srgrimes		if (!strcmp("ffactor", s)) {
6281573Srgrimes			ih.ffactor = atoi(eq);
6291573Srgrimes			return (&ih);
6301573Srgrimes		}
6311573Srgrimes		if (!strcmp("nelem", s)) {
6321573Srgrimes			ih.nelem = atoi(eq);
6331573Srgrimes			return (&ih);
6341573Srgrimes		}
6351573Srgrimes		if (!strcmp("cachesize", s)) {
6361573Srgrimes			ih.cachesize = atoi(eq);
6371573Srgrimes			return (&ih);
6381573Srgrimes		}
6391573Srgrimes		if (!strcmp("lorder", s)) {
6401573Srgrimes			ih.lorder = atoi(eq);
6411573Srgrimes			return (&ih);
6421573Srgrimes		}
6431573Srgrimes		break;
6441573Srgrimes	case DB_RECNO:
6451573Srgrimes		if (!strcmp("flags", s)) {
6461573Srgrimes			rh.flags = atoi(eq);
6471573Srgrimes			return (&rh);
6481573Srgrimes		}
6491573Srgrimes		if (!strcmp("cachesize", s)) {
6501573Srgrimes			rh.cachesize = atoi(eq);
6511573Srgrimes			return (&rh);
6521573Srgrimes		}
6531573Srgrimes		if (!strcmp("lorder", s)) {
6541573Srgrimes			rh.lorder = atoi(eq);
6551573Srgrimes			return (&rh);
6561573Srgrimes		}
6571573Srgrimes		if (!strcmp("reclen", s)) {
6581573Srgrimes			rh.reclen = atoi(eq);
6591573Srgrimes			return (&rh);
6601573Srgrimes		}
6611573Srgrimes		if (!strcmp("bval", s)) {
6621573Srgrimes			rh.bval = atoi(eq);
6631573Srgrimes			return (&rh);
6641573Srgrimes		}
6651573Srgrimes		if (!strcmp("psize", s)) {
6661573Srgrimes			rh.psize = atoi(eq);
6671573Srgrimes			return (&rh);
6681573Srgrimes		}
6691573Srgrimes		break;
6701573Srgrimes	}
6711573Srgrimes	err("%s: unknown structure value", s);
6721573Srgrimes	/* NOTREACHED */
6731573Srgrimes}
6741573Srgrimes
6751573Srgrimesvoid *
6761573Srgrimesrfile(name, lenp)
6771573Srgrimes	char *name;
6781573Srgrimes	size_t *lenp;
6791573Srgrimes{
6801573Srgrimes	struct stat sb;
6811573Srgrimes	void *p;
6821573Srgrimes	int fd;
6831573Srgrimes	char *np, *index();
6841573Srgrimes
6851573Srgrimes	for (; isspace(*name); ++name);
6861573Srgrimes	if ((np = index(name, '\n')) != NULL)
6871573Srgrimes		*np = '\0';
6881573Srgrimes	if ((fd = open(name, O_RDONLY, 0)) < 0 ||
6891573Srgrimes	    fstat(fd, &sb))
6901573Srgrimes		err("%s: %s\n", name, strerror(errno));
6911573Srgrimes#ifdef NOT_PORTABLE
6921573Srgrimes	if (sb.st_size > (off_t)SIZE_T_MAX)
6931573Srgrimes		err("%s: %s\n", name, strerror(E2BIG));
6941573Srgrimes#endif
6951573Srgrimes	if ((p = (void *)malloc((u_int)sb.st_size)) == NULL)
6961573Srgrimes		err("%s", strerror(errno));
6971573Srgrimes	(void)read(fd, p, (int)sb.st_size);
6981573Srgrimes	*lenp = sb.st_size;
6991573Srgrimes	(void)close(fd);
7001573Srgrimes	return (p);
7011573Srgrimes}
7021573Srgrimes
7031573Srgrimesvoid *
7041573Srgrimesxmalloc(text, len)
7051573Srgrimes	char *text;
7061573Srgrimes	size_t len;
7071573Srgrimes{
7081573Srgrimes	void *p;
7091573Srgrimes
7101573Srgrimes	if ((p = (void *)malloc(len)) == NULL)
7111573Srgrimes		err("%s", strerror(errno));
7121573Srgrimes	memmove(p, text, len);
7131573Srgrimes	return (p);
7141573Srgrimes}
7151573Srgrimes
7161573Srgrimesvoid
7171573Srgrimesusage()
7181573Srgrimes{
7191573Srgrimes	(void)fprintf(stderr,
7201573Srgrimes	    "usage: dbtest [-l] [-f file] [-i info] [-o file] type script\n");
7211573Srgrimes	exit(1);
7221573Srgrimes}
7231573Srgrimes
7241573Srgrimes#include <stdarg.h>
7251573Srgrimes
7261573Srgrimesvoid
7271573Srgrimeserr(const char *fmt, ...)
7281573Srgrimes{
7291573Srgrimes	va_list ap;
73097407Salfred
7311573Srgrimes	va_start(ap, fmt);
7321573Srgrimes	(void)fprintf(stderr, "dbtest: ");
7331573Srgrimes	(void)vfprintf(stderr, fmt, ap);
7341573Srgrimes	va_end(ap);
7351573Srgrimes	(void)fprintf(stderr, "\n");
7361573Srgrimes	exit(1);
7371573Srgrimes	/* NOTREACHED */
7381573Srgrimes}
739