xref: /csrg-svn/lib/libc/db/test/dbtest.c (revision 56039)
1 /*-
2  * Copyright (c) 1992 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 char copyright[] =
10 "@(#) Copyright (c) 1992 The Regents of the University of California.\n\
11  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)dbtest.c	5.1 (Berkeley) 08/26/92";
16 #endif /* not lint */
17 
18 #include <sys/param.h>
19 #include <sys/stat.h>
20 
21 #include <ctype.h>
22 #include <db.h>
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <limits.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 
31 enum S { COMMAND, GET, PUT, REMOVE, SEQ, SEQFLAG, KEY, DATA };
32 
33 DBTYPE	 dbtype __P((char *));
34 void	 err __P((const char *, ...));
35 void	 get __P((DB *, DBT *));
36 void	 put __P((DB *, DBT *, DBT *));
37 void	 rem __P((DB *, DBT *));
38 void	*rfile __P((char *, size_t *));
39 void	 seq __P((DB *));
40 u_int	 setflags __P((char *));
41 void	*setinfo __P((DBTYPE, char *));
42 void	 usage __P((void));
43 void	*xmalloc __P((char *, size_t));
44 
45 DBTYPE type;
46 void *infop;
47 u_long lineno;
48 u_int flags;
49 int ofd = STDOUT_FILENO;
50 
51 int
52 main(argc, argv)
53 	int argc;
54 	char *argv[];
55 {
56 	enum S command, state;
57 	DB *dbp;
58 	DBT data, key;
59 	size_t len;
60 	int ch;
61 	char *infoarg, *p, buf[8 * 1024];
62 
63 	infoarg = NULL;
64 	while ((ch = getopt(argc, argv, "i:o:")) != EOF)
65 		switch(ch) {
66 		case 'i':
67 			infoarg = optarg;
68 			break;
69 		case 'o':
70 			if ((ofd = open(optarg,
71 			    O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
72 				err("%s: %s", optarg, strerror(errno));
73 			break;
74 		case '?':
75 		default:
76 			usage();
77 		}
78 	argc -= optind;
79 	argv += optind;
80 
81 	if (argc != 2)
82 		usage();
83 
84 	/* Set the type. */
85 	type = dbtype(*argv++);
86 
87 	/* Open the descriptor file. */
88 	if (freopen(*argv, "r", stdin) == NULL)
89 		err("%s: %s", *argv, strerror(errno));
90 
91 	/* Set up the db structure as necessary. */
92 	if (infoarg == NULL)
93 		infop = NULL;
94 	else
95 		while ((p = strsep(&infoarg, ",\t ")) != NULL)
96 			if (*p != '\0')
97 				infop = setinfo(type, p);
98 
99 #define	BACKINGFILE	"/tmp/__dbtest"
100 	/* Open the DB. */
101 	(void)unlink(BACKINGFILE);
102 	if ((dbp = dbopen(BACKINGFILE,
103 	    O_CREAT | O_RDWR, S_IRUSR | S_IWUSR, type, infop)) == NULL)
104 		err("dbopen: %s", strerror(errno));
105 
106 	state = COMMAND;
107 	for (lineno = 1;
108 	    (p = fgets(buf, sizeof(buf), stdin)) != NULL; ++lineno) {
109 		len = strlen(buf);
110 		switch(*p) {
111 		case 'g':			/* get */
112 			if (state != COMMAND)
113 				err("line %lu: not expecting command", lineno);
114 			state = KEY;
115 			command = GET;
116 			break;
117 		case 'p':			/* put */
118 			if (state != COMMAND)
119 				err("line %lu: not expecting command", lineno);
120 			state = KEY;
121 			command = PUT;
122 			break;
123 		case 'r':			/* remove */
124 			if (state != COMMAND)
125 				err("line %lu: not expecting command", lineno);
126 			state = KEY;
127 			command = REMOVE;
128 			break;
129 		case 's':			/* seq */
130 			if (state != COMMAND)
131 				err("line %lu: not expecting command", lineno);
132 			seq(dbp);
133 			break;
134 		case 'f':
135 			flags |= setflags(p + 1);
136 			break;
137 		case 'D':			/* data file */
138 			if (state != DATA)
139 				err("line %lu: not expecting data", lineno);
140 			if (command != PUT)
141 				err("line %lu: command doesn't take data",
142 				    lineno);
143 			data.data = rfile(p + 1, &data.size);
144 			put(dbp, &key, &data);
145 			free(key.data);
146 			free(data.data);
147 			state = COMMAND;
148 			break;
149 		case 'd':			/* data */
150 			if (state != DATA)
151 				err("line %lu: not expecting data", lineno);
152 			if (command != PUT)
153 				err("line %lu: command doesn't take data",
154 				    lineno);
155 			data.data = xmalloc(p + 1, len - 1);
156 			data.size = len - 1;
157 			put(dbp, &key, &data);
158 			free(key.data);
159 			free(data.data);
160 			state = COMMAND;
161 			break;
162 		case 'K':			/* key file */
163 			if (state != KEY)
164 				err("line %lu: not expecting a key", lineno);
165 			if (type == DB_RECNO)
166 				err("line %lu: 'K' not available for recno",
167 				    lineno);
168 			key.data = rfile(p + 1, &key.size);
169 			switch(command) {
170 			case GET:
171 				get(dbp, &key);
172 				free(key.data);
173 				state = COMMAND;
174 				break;
175 			case PUT:
176 				state = DATA;
177 				break;
178 			case REMOVE:
179 				rem(dbp, &key);
180 				free(key.data);
181 				state = COMMAND;
182 				break;
183 			default:
184 				err("line %lu: command doesn't take a key",
185 				    lineno);
186 			}
187 			break;
188 		case 'k':			/* key */
189 			if (state != KEY)
190 				err("line %lu: not expecting a key", lineno);
191 			if (type == DB_RECNO) {
192 				static recno_t recno;
193 				recno = strtol(p + 1, NULL, 0);
194 				key.data = &recno;
195 				key.size = sizeof(recno);
196 			} else {
197 				key.data = xmalloc(p + 1, len - 1);
198 				key.size = len - 1;
199 			}
200 			switch(command) {
201 			case GET:
202 				get(dbp, &key);
203 				if (type != DB_RECNO)
204 					free(key.data);
205 				state = COMMAND;
206 				break;
207 			case PUT:
208 				state = DATA;
209 				break;
210 			case REMOVE:
211 				rem(dbp, &key);
212 				if (type != DB_RECNO)
213 					free(key.data);
214 				state = COMMAND;
215 				break;
216 			default:
217 				err("line %lu: command doesn't take a key",
218 				    lineno);
219 			}
220 			break;
221 		default:
222 			err("line %lu: %s: unknown command character",
223 			    *p, lineno);
224 		}
225 	}
226 	(void)close(ofd);
227 	exit(0);
228 }
229 
230 void
231 get(dbp, kp)
232 	DB *dbp;
233 	DBT *kp;
234 {
235 	DBT data;
236 
237 	if (dbp->get(dbp, kp, &data, flags) == -1)
238 		err("line %lu: get: %s", lineno, strerror(errno));
239 	(void)write(ofd, data.data, data.size);
240 }
241 
242 void
243 put(dbp, kp, dp)
244 	DB *dbp;
245 	DBT *kp, *dp;
246 {
247 	if (dbp->put(dbp, kp, dp, flags) == -1)
248 		err("line %lu: put: %s", lineno, strerror(errno));
249 }
250 
251 void
252 rem(dbp, kp)
253 	DB *dbp;
254 	DBT *kp;
255 {
256 	if (dbp->del(dbp, kp, flags) == -1)
257 		err("line %lu: get: %s", lineno, strerror(errno));
258 }
259 
260 void
261 seq(dbp)
262 	DB *dbp;
263 {
264 	DBT key, data;
265 	size_t len;
266 	char nbuf[20];
267 
268 	if (dbp->seq(dbp, &key, &data, flags) == -1)
269 		err("line %lu: seq: %s", lineno, strerror(errno));
270 	if (type == DB_RECNO) {
271 		len = sprintf(nbuf, "%lu\n", *(u_long *)key.data);
272 		(void)write(ofd, nbuf, len);
273 	} else
274 		(void)write(ofd, key.data, key.size);
275 	(void)write(ofd, data.data, data.size);
276 }
277 
278 u_int
279 setflags(s)
280 	char *s;
281 {
282 	char *p;
283 
284 	for (; isspace(*s); ++s);
285 	if (*s == '\n')
286 		return (0);
287 	if ((p = index(s, '\n')) != NULL)
288 		*p = '\0';
289 	if (!strcmp(s, "R_APPEND"))
290 		return (R_APPEND);
291 	if (!strcmp(s, "R_CURSOR"))
292 		return (R_CURSOR);
293 	if (!strcmp(s, "R_IAFTER"))
294 		return (R_IAFTER);
295 	if (!strcmp(s, "R_IBEFORE"))
296 		return (R_IBEFORE);
297 	if (!strcmp(s, "R_NOOVERWRITE"))
298 		return (R_NOOVERWRITE);
299 	if (!strcmp(s, "R_FIRST"))
300 		return (R_FIRST);
301 	if (!strcmp(s, "R_LAST"))
302 		return (R_LAST);
303 	if (!strcmp(s, "R_NEXT"))
304 		return (R_NEXT);
305 	if (!strcmp(s, "R_PREV"))
306 		return (R_PREV);
307 	err("line %lu: %s: unknown flag", lineno, s);
308 	/* NOTREACHED */
309 }
310 
311 DBTYPE
312 dbtype(s)
313 	char *s;
314 {
315 	if (!strcmp(s, "btree"))
316 		return (DB_BTREE);
317 	if (!strcmp(s, "hash"))
318 		return (DB_HASH);
319 	if (!strcmp(s, "recno"))
320 		return (DB_RECNO);
321 	err("%s: unknown type (use btree, hash or recno)", s);
322 	/* NOTREACHED */
323 }
324 
325 void *
326 setinfo(type, s)
327 	DBTYPE type;
328 	char *s;
329 {
330 	static BTREEINFO ib;
331 	static HASHINFO ih;
332 	static RECNOINFO rh;
333 	char *eq;
334 
335 	if ((eq = index(s, '=')) == NULL)
336 		err("%s: illegal structure set statement", s);
337 	*eq++ = '\0';
338 	if (!isdigit(*eq))
339 		err("%s: structure set statement must be a number", s);
340 
341 	switch(type) {
342 	case DB_BTREE:
343 		if (!strcmp("flags", s)) {
344 			ib.flags = strtoul(eq, NULL, 0);
345 			return (&ib);
346 		}
347 		if (!strcmp("cachesize", s)) {
348 			ib.cachesize = strtoul(eq, NULL, 0);
349 			return (&ib);
350 		}
351 		if (!strcmp("maxkeypage", s)) {
352 			ib.maxkeypage = strtoul(eq, NULL, 0);
353 			return (&ib);
354 		}
355 		if (!strcmp("minkeypage", s)) {
356 			ib.minkeypage = strtoul(eq, NULL, 0);
357 			return (&ib);
358 		}
359 		if (!strcmp("lorder", s)) {
360 			ib.lorder = strtoul(eq, NULL, 0);
361 			return (&ib);
362 		}
363 		break;
364 	case DB_HASH:
365 		if (!strcmp("bsize", s)) {
366 			ih.bsize = strtoul(eq, NULL, 0);
367 			return (&ib);
368 		}
369 		if (!strcmp("ffactor", s)) {
370 			ih.ffactor = strtoul(eq, NULL, 0);
371 			return (&ib);
372 		}
373 		if (!strcmp("nelem", s)) {
374 			ih.nelem = strtoul(eq, NULL, 0);
375 			return (&ib);
376 		}
377 		if (!strcmp("cachesize", s)) {
378 			ih.cachesize = strtoul(eq, NULL, 0);
379 			return (&ib);
380 		}
381 		if (!strcmp("lorder", s)) {
382 			ih.lorder = strtoul(eq, NULL, 0);
383 			return (&ib);
384 		}
385 		break;
386 	case DB_RECNO:
387 		if (!strcmp("flags", s)) {
388 			rh.flags = strtoul(eq, NULL, 0);
389 			return (&ib);
390 		}
391 		if (!strcmp("cachesize", s)) {
392 			rh.cachesize = strtoul(eq, NULL, 0);
393 			return (&ib);
394 		}
395 		if (!strcmp("lorder", s)) {
396 			rh.lorder = strtoul(eq, NULL, 0);
397 			return (&ib);
398 		}
399 		if (!strcmp("reclen", s)) {
400 			rh.reclen = strtoul(eq, NULL, 0);
401 			return (&ib);
402 		}
403 		if (!strcmp("bval", s)) {
404 			rh.bval = strtoul(eq, NULL, 0);
405 			return (&ib);
406 		}
407 		break;
408 	}
409 	err("%s: unknown structure value", s);
410 	/* NOTREACHED */
411 }
412 
413 void *
414 rfile(name, lenp)
415 	char *name;
416 	size_t *lenp;
417 {
418 	struct stat sb;
419 	void *p;
420 	int fd;
421 	char *np;
422 
423 	for (; isspace(*name); ++name);
424 	if ((np = index(name, '\n')) != NULL)
425 		*np = '\0';
426 	if ((fd = open(name, O_RDONLY, 0)) < 0 ||
427 	    fstat(fd, &sb))
428 		err("%s: %s\n", name, strerror(errno));
429 	if (sb.st_size > SIZE_T_MAX)
430 		err("%s: %s\n", name, strerror(E2BIG));
431 	if ((p = malloc((u_int)sb.st_size)) == NULL)
432 		err("%s", strerror(errno));
433 	(void)read(fd, p, (int)sb.st_size);
434 	*lenp = sb.st_size;
435 	return (p);
436 }
437 
438 void *
439 xmalloc(text, len)
440 	char *text;
441 	size_t len;
442 {
443 	void *p;
444 
445 	if ((p = malloc(len)) == NULL)
446 		err("%s", strerror(errno));
447 	bcopy(text, p, len);
448 	return (p);
449 }
450 
451 void
452 usage()
453 {
454 	(void)fprintf(stderr,
455 	    "usage: dbtest [-i info] [-o file] type script\n");
456 	exit(1);
457 }
458 
459 #if __STDC__
460 #include <stdarg.h>
461 #else
462 #include <varargs.h>
463 #endif
464 
465 void
466 #if __STDC__
467 err(const char *fmt, ...)
468 #else
469 err(fmt, va_alist)
470 	char *fmt;
471         va_dcl
472 #endif
473 {
474 	va_list ap;
475 #if __STDC__
476 	va_start(ap, fmt);
477 #else
478 	va_start(ap);
479 #endif
480 	(void)fprintf(stderr, "dbtest: ");
481 	(void)vfprintf(stderr, fmt, ap);
482 	va_end(ap);
483 	(void)fprintf(stderr, "\n");
484 	exit(1);
485 	/* NOTREACHED */
486 }
487