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