1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1997,2008 Oracle.  All rights reserved.
5 *
6 * $Id: ex_btrec.c,v 12.7 2008/01/08 20:58:23 bostic Exp $
7 */
8
9#include <sys/types.h>
10
11#include <errno.h>
12#include <stdlib.h>
13#include <string.h>
14
15#include <db.h>
16
17#define	DATABASE	"access.db"
18#define	WORDLIST	"../test/wordlist"
19int	main __P((void));
20
21int	ex_btrec __P((void));
22void	show __P((const char *, DBT *, DBT *));
23
24int
25main()
26{
27	return (ex_btrec() == 1 ? EXIT_FAILURE : EXIT_SUCCESS);
28}
29
30int
31ex_btrec()
32{
33	DB *dbp;
34	DBC *dbcp;
35	DBT key, data;
36	DB_BTREE_STAT *statp;
37	FILE *fp;
38	db_recno_t recno;
39	size_t len;
40	int cnt, ret;
41	char *p, *t, buf[1024], rbuf[1024];
42	const char *progname = "ex_btrec";		/* Program name. */
43
44	/* Open the word database. */
45	if ((fp = fopen(WORDLIST, "r")) == NULL) {
46		fprintf(stderr, "%s: open %s: %s\n",
47		    progname, WORDLIST, db_strerror(errno));
48		return (1);
49	}
50
51	/* Remove the previous database. */
52	(void)remove(DATABASE);
53
54	/* Create and initialize database object, open the database. */
55	if ((ret = db_create(&dbp, NULL, 0)) != 0) {
56		fprintf(stderr,
57		    "%s: db_create: %s\n", progname, db_strerror(ret));
58		return (1);
59	}
60	dbp->set_errfile(dbp, stderr);
61	dbp->set_errpfx(dbp, progname);			/* 1K page sizes. */
62	if ((ret = dbp->set_pagesize(dbp, 1024)) != 0) {
63		dbp->err(dbp, ret, "set_pagesize");
64		return (1);
65	}						/* Record numbers. */
66	if ((ret = dbp->set_flags(dbp, DB_RECNUM)) != 0) {
67		dbp->err(dbp, ret, "set_flags: DB_RECNUM");
68		return (1);
69	}
70	if ((ret = dbp->open(dbp,
71	    NULL, DATABASE, NULL, DB_BTREE, DB_CREATE, 0664)) != 0) {
72		dbp->err(dbp, ret, "open: %s", DATABASE);
73		return (1);
74	}
75
76	/*
77	 * Insert records into the database, where the key is the word
78	 * preceded by its record number, and the data is the same, but
79	 * in reverse order.
80	 */
81	memset(&key, 0, sizeof(DBT));
82	memset(&data, 0, sizeof(DBT));
83	for (cnt = 1; cnt <= 1000; ++cnt) {
84		(void)sprintf(buf, "%04d_", cnt);
85		if (fgets(buf + 4, sizeof(buf) - 4, fp) == NULL)
86			break;
87		len = strlen(buf);
88		for (t = rbuf, p = buf + (len - 2); p >= buf;)
89			*t++ = *p--;
90		*t++ = '\0';
91
92		key.data = buf;
93		data.data = rbuf;
94		data.size = key.size = (u_int32_t)len - 1;
95
96		if ((ret =
97		    dbp->put(dbp, NULL, &key, &data, DB_NOOVERWRITE)) != 0) {
98			dbp->err(dbp, ret, "DB->put");
99			if (ret != DB_KEYEXIST)
100				goto err1;
101		}
102	}
103
104	/* Close the word database. */
105	(void)fclose(fp);
106
107	/* Print out the number of records in the database. */
108	if ((ret = dbp->stat(dbp, NULL, &statp, 0)) != 0) {
109		dbp->err(dbp, ret, "DB->stat");
110		goto err1;
111	}
112	printf("%s: database contains %lu records\n",
113	    progname, (u_long)statp->bt_ndata);
114	free(statp);
115
116	/* Acquire a cursor for the database. */
117	if ((ret = dbp->cursor(dbp, NULL, &dbcp, 0)) != 0) {
118		dbp->err(dbp, ret, "DB->cursor");
119		goto err1;
120	}
121
122	/*
123	 * Prompt the user for a record number, then retrieve and display
124	 * that record.
125	 */
126	for (;;) {
127		/* Get a record number. */
128		printf("recno #> ");
129		fflush(stdout);
130		if (fgets(buf, sizeof(buf), stdin) == NULL)
131			break;
132		recno = atoi(buf);
133
134		/*
135		 * Reset the key each time, the dbp->get() routine returns
136		 * the key and data pair, not just the key!
137		 */
138		key.data = &recno;
139		key.size = sizeof(recno);
140		if ((ret = dbcp->get(dbcp, &key, &data, DB_SET_RECNO)) != 0)
141			goto get_err;
142
143		/* Display the key and data. */
144		show("k/d\t", &key, &data);
145
146		/* Move the cursor a record forward. */
147		if ((ret = dbcp->get(dbcp, &key, &data, DB_NEXT)) != 0)
148			goto get_err;
149
150		/* Display the key and data. */
151		show("next\t", &key, &data);
152
153		/*
154		 * Retrieve the record number for the following record into
155		 * local memory.
156		 */
157		data.data = &recno;
158		data.size = sizeof(recno);
159		data.ulen = sizeof(recno);
160		data.flags |= DB_DBT_USERMEM;
161		if ((ret = dbcp->get(dbcp, &key, &data, DB_GET_RECNO)) != 0) {
162get_err:		dbp->err(dbp, ret, "DBcursor->get");
163			if (ret != DB_NOTFOUND && ret != DB_KEYEMPTY)
164				goto err2;
165		} else
166			printf("retrieved recno: %lu\n", (u_long)recno);
167
168		/* Reset the data DBT. */
169		memset(&data, 0, sizeof(data));
170	}
171
172	if ((ret = dbcp->close(dbcp)) != 0) {
173		dbp->err(dbp, ret, "DBcursor->close");
174		goto err1;
175	}
176	if ((ret = dbp->close(dbp, 0)) != 0) {
177		fprintf(stderr,
178		    "%s: DB->close: %s\n", progname, db_strerror(ret));
179		return (1);
180	}
181
182	return (0);
183
184err2:	(void)dbcp->close(dbcp);
185err1:	(void)dbp->close(dbp, 0);
186	return (ret);
187
188}
189
190/*
191 * show --
192 *	Display a key/data pair.
193 */
194void
195show(msg, key, data)
196	const char *msg;
197	DBT *key, *data;
198{
199	printf("%s%.*s : %.*s\n", msg,
200	    (int)key->size, (char *)key->data,
201	    (int)data->size, (char *)data->data);
202}
203