xref: /original-bsd/lib/libc/db/test/btree.tests/main.c (revision c3e32dec)
1 /*-
2  * Copyright (c) 1990, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Mike Olson.
7  *
8  * %sccs.include.redist.c%
9  */
10 
11 #if defined(LIBC_SCCS) && !defined(lint)
12 static char sccsid[] = "@(#)main.c	8.1 (Berkeley) 06/04/93";
13 #endif /* LIBC_SCCS and not lint */
14 
15 #include <sys/param.h>
16 #include <fcntl.h>
17 #include <db.h>
18 #include <errno.h>
19 #include <stdio.h>
20 #include <ctype.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include "btree.h"
24 
25 typedef struct cmd_table {
26 	char *cmd;
27 	int nargs;
28 	int rconv;
29 	void (*func) __P((DB *, char **));
30 	char *usage, *descrip;
31 } cmd_table;
32 
33 int stopstop;
34 DB *globaldb;
35 
36 void append	__P((DB *, char **));
37 void bstat	__P((DB *, char **));
38 void cursor	__P((DB *, char **));
39 void delcur	__P((DB *, char **));
40 void delete	__P((DB *, char **));
41 void dump	__P((DB *, char **));
42 void first	__P((DB *, char **));
43 void get	__P((DB *, char **));
44 void help	__P((DB *, char **));
45 void iafter	__P((DB *, char **));
46 void ibefore	__P((DB *, char **));
47 void icursor	__P((DB *, char **));
48 void insert	__P((DB *, char **));
49 void keydata	__P((DBT *, DBT *));
50 void last	__P((DB *, char **));
51 void list	__P((DB *, char **));
52 void load	__P((DB *, char **));
53 void mstat	__P((DB *, char **));
54 void next	__P((DB *, char **));
55 int  parse	__P((char *, char **, int));
56 void previous	__P((DB *, char **));
57 void show	__P((DB *, char **));
58 void usage	__P((void));
59 void user	__P((DB *));
60 
61 cmd_table commands[] = {
62 	"?",	0, 0, help, "help", NULL,
63 	"a",	2, 1, append, "append key def", "append key with data def",
64 	"b",	0, 0, bstat, "bstat", "stat btree",
65 	"c",	1, 1, cursor,  "cursor word", "move cursor to word",
66 	"delc",	0, 0, delcur, "delcur", "delete key the cursor references",
67 	"dele",	1, 1, delete, "delete word", "delete word",
68 	"d",	0, 0, dump, "dump", "dump database",
69 	"f",	0, 0, first, "first", "move cursor to first record",
70 	"g",	1, 1, get, "get key", "locate key",
71 	"h",	0, 0, help, "help", "print command summary",
72 	"ia",	2, 1, iafter, "iafter key data", "insert data after key",
73 	"ib",	2, 1, ibefore, "ibefore key data", "insert data before key",
74 	"ic",	2, 1, icursor, "icursor key data", "replace cursor",
75 	"in",	2, 1, insert, "insert key def", "insert key with data def",
76 	"la",	0, 0, last, "last", "move cursor to last record",
77 	"li",	1, 1, list, "list file", "list to a file",
78 	"loa",	1, 0, load, "load file", NULL,
79 	"loc",	1, 1, get, "get key", NULL,
80 	"m",	0, 0, mstat, "mstat", "stat memory pool",
81 	"n",	0, 0, next, "next", "move cursor forward one record",
82 	"p",	0, 0, previous, "previous", "move cursor back one record",
83 	"q",	0, 0, NULL, "quit", "quit",
84 	"sh",	1, 0, show, "show page", "dump a page",
85 	{ NULL },
86 };
87 
88 int recno;					/* use record numbers */
89 char *dict = "words";				/* default dictionary */
90 char *progname;
91 
92 int
93 main(argc, argv)
94 	int argc;
95 	char **argv;
96 {
97 	int c;
98 	DB *db;
99 	BTREEINFO b;
100 
101 	progname = *argv;
102 
103 	b.flags = 0;
104 	b.cachesize = 0;
105 	b.maxkeypage = 0;
106 	b.minkeypage = 0;
107 	b.psize = 0;
108 	b.compare = NULL;
109 	b.prefix = NULL;
110 	b.lorder = 0;
111 
112 	while ((c = getopt(argc, argv, "bc:di:lp:ru")) != EOF) {
113 		switch (c) {
114 		case 'b':
115 			b.lorder = BIG_ENDIAN;
116 			break;
117 		case 'c':
118 			b.cachesize = atoi(optarg);
119 			break;
120 		case 'd':
121 			b.flags |= R_DUP;
122 			break;
123 		case 'i':
124 			dict = optarg;
125 			break;
126 		case 'l':
127 			b.lorder = LITTLE_ENDIAN;
128 			break;
129 		case 'p':
130 			b.psize = atoi(optarg);
131 			break;
132 		case 'r':
133 			recno = 1;
134 			break;
135 		case 'u':
136 			b.flags = 0;
137 			break;
138 		default:
139 			usage();
140 		}
141 	}
142 	argc -= optind;
143 	argv += optind;
144 
145 	if (recno)
146 		db = dbopen(*argv == NULL ? NULL : *argv, O_RDWR,
147 		    0, DB_RECNO, NULL);
148 	else
149 		db = dbopen(*argv == NULL ? NULL : *argv, O_CREAT|O_RDWR,
150 		    0600, DB_BTREE, &b);
151 
152 	if (db == NULL) {
153 		(void)fprintf(stderr, "dbopen: %s\n", strerror(errno));
154 		exit(1);
155 	}
156 	globaldb = db;
157 	user(db);
158 	exit(0);
159 	/* NOTREACHED */
160 }
161 
162 void
163 user(db)
164 	DB *db;
165 {
166 	FILE *ifp;
167 	int argc, i, last;
168 	char *lbuf, *argv[4], buf[512];
169 
170 	if ((ifp = fopen("/dev/tty", "r")) == NULL) {
171 		(void)fprintf(stderr,
172 		    "/dev/tty: %s\n", strerror(errno));
173 		exit(1);
174 	}
175 	for (last = 0;;) {
176 		(void)printf("> ");
177 		(void)fflush(stdout);
178 		if ((lbuf = fgets(&buf[0], 512, ifp)) == NULL)
179 			break;
180 		if (lbuf[0] == '\n') {
181 			i = last;
182 			goto uselast;
183 		}
184 		lbuf[strlen(lbuf) - 1] = '\0';
185 
186 		if (lbuf[0] == 'q')
187 			break;
188 
189 		argc = parse(lbuf, &argv[0], 3);
190 		if (argc == 0)
191 			continue;
192 
193 		for (i = 0; commands[i].cmd != NULL; i++)
194 			if (strncmp(commands[i].cmd, argv[0],
195 			    strlen(commands[i].cmd)) == 0)
196 				break;
197 
198 		if (commands[i].cmd == NULL) {
199 			(void)fprintf(stderr,
200 			    "%s: command unknown ('help' for help)\n", lbuf);
201 			continue;
202 		}
203 
204 		if (commands[i].nargs != argc - 1) {
205 			(void)fprintf(stderr, "usage: %s\n", commands[i].usage);
206 			continue;
207 		}
208 
209 		if (recno && commands[i].rconv) {
210 			static recno_t nlong;
211 			nlong = atoi(argv[1]);
212 			argv[1] = (char *)&nlong;
213 		}
214 uselast:	last = i;
215 		(*commands[i].func)(db, argv);
216 	}
217 	if ((db->sync)(db) == RET_ERROR)
218 		perror("dbsync");
219 	else if ((db->close)(db) == RET_ERROR)
220 		perror("dbclose");
221 }
222 
223 int
224 parse(lbuf, argv, maxargc)
225 	char *lbuf, **argv;
226 	int maxargc;
227 {
228 	int argc = 0;
229 	char *c;
230 
231 	c = lbuf;
232 	while (isspace(*c))
233 		c++;
234 	while (*c != '\0' && argc < maxargc) {
235 		*argv++ = c;
236 		argc++;
237 		while (!isspace(*c) && *c != '\0') {
238 			c++;
239 		}
240 		while (isspace(*c))
241 			*c++ = '\0';
242 	}
243 	return (argc);
244 }
245 
246 void
247 append(db, argv)
248 	DB *db;
249 	char **argv;
250 {
251 	DBT key, data;
252 	int status;
253 
254 	if (!recno) {
255 		(void)fprintf(stderr,
256 		    "append only available for recno db's.\n");
257 		return;
258 	}
259 	key.data = argv[1];
260 	key.size = sizeof(recno_t);
261 	data.data = argv[2];
262 	data.size = strlen(data.data);
263 	status = (db->put)(db, &key, &data, R_APPEND);
264 	switch (status) {
265 	case RET_ERROR:
266 		perror("append/put");
267 		break;
268 	case RET_SPECIAL:
269 		(void)printf("%s (duplicate key)\n", argv[1]);
270 		break;
271 	case RET_SUCCESS:
272 		break;
273 	}
274 }
275 
276 void
277 cursor(db, argv)
278 	DB *db;
279 	char **argv;
280 {
281 	DBT data, key;
282 	int status;
283 
284 	key.data = argv[1];
285 	if (recno)
286 		key.size = sizeof(recno_t);
287 	else
288 		key.size = strlen(argv[1]) + 1;
289 	status = (*db->seq)(db, &key, &data, R_CURSOR);
290 	switch (status) {
291 	case RET_ERROR:
292 		perror("cursor/seq");
293 		break;
294 	case RET_SPECIAL:
295 		(void)printf("key not found\n");
296 		break;
297 	case RET_SUCCESS:
298 		keydata(&key, &data);
299 		break;
300 	}
301 }
302 
303 void
304 delcur(db, argv)
305 	DB *db;
306 	char **argv;
307 {
308 	int status;
309 
310 	status = (*db->del)(db, NULL, R_CURSOR);
311 
312 	if (status == RET_ERROR)
313 		perror("delcur/del");
314 }
315 
316 void
317 delete(db, argv)
318 	DB *db;
319 	char **argv;
320 {
321 	DBT key;
322 	int status;
323 
324 	key.data = argv[1];
325 	if (recno)
326 		key.size = sizeof(recno_t);
327 	else
328 		key.size = strlen(argv[1]) + 1;
329 
330 	status = (*db->del)(db, &key, 0);
331 	switch (status) {
332 	case RET_ERROR:
333 		perror("delete/del");
334 		break;
335 	case RET_SPECIAL:
336 		(void)printf("key not found\n");
337 		break;
338 	case RET_SUCCESS:
339 		break;
340 	}
341 }
342 
343 void
344 dump(db, argv)
345 	DB *db;
346 	char **argv;
347 {
348 	__bt_dump(db);
349 }
350 
351 void
352 first(db, argv)
353 	DB *db;
354 	char **argv;
355 {
356 	DBT data, key;
357 	int status;
358 
359 	status = (*db->seq)(db, &key, &data, R_FIRST);
360 
361 	switch (status) {
362 	case RET_ERROR:
363 		perror("first/seq");
364 		break;
365 	case RET_SPECIAL:
366 		(void)printf("no more keys\n");
367 		break;
368 	case RET_SUCCESS:
369 		keydata(&key, &data);
370 		break;
371 	}
372 }
373 
374 void
375 get(db, argv)
376 	DB *db;
377 	char **argv;
378 {
379 	DBT data, key;
380 	int status;
381 
382 	key.data = argv[1];
383 	if (recno)
384 		key.size = sizeof(recno_t);
385 	else
386 		key.size = strlen(argv[1]) + 1;
387 
388 	status = (*db->get)(db, &key, &data, 0);
389 
390 	switch (status) {
391 	case RET_ERROR:
392 		perror("get/get");
393 		break;
394 	case RET_SPECIAL:
395 		(void)printf("key not found\n");
396 		break;
397 	case RET_SUCCESS:
398 		keydata(&key, &data);
399 		break;
400 	}
401 }
402 
403 void
404 help(db, argv)
405 	DB *db;
406 	char **argv;
407 {
408 	int i;
409 
410 	for (i = 0; commands[i].cmd; i++)
411 		if (commands[i].descrip)
412 			(void)printf("%s: %s\n",
413 			    commands[i].usage, commands[i].descrip);
414 }
415 
416 void
417 iafter(db, argv)
418 	DB *db;
419 	char **argv;
420 {
421 	DBT key, data;
422 	int status;
423 
424 	if (!recno) {
425 		(void)fprintf(stderr,
426 		    "iafter only available for recno db's.\n");
427 		return;
428 	}
429 	key.data = argv[1];
430 	key.size = sizeof(recno_t);
431 	data.data = argv[2];
432 	data.size = strlen(data.data);
433 	status = (db->put)(db, &key, &data, R_IAFTER);
434 	switch (status) {
435 	case RET_ERROR:
436 		perror("iafter/put");
437 		break;
438 	case RET_SPECIAL:
439 		(void)printf("%s (duplicate key)\n", argv[1]);
440 		break;
441 	case RET_SUCCESS:
442 		break;
443 	}
444 }
445 
446 void
447 ibefore(db, argv)
448 	DB *db;
449 	char **argv;
450 {
451 	DBT key, data;
452 	int status;
453 
454 	if (!recno) {
455 		(void)fprintf(stderr,
456 		    "ibefore only available for recno db's.\n");
457 		return;
458 	}
459 	key.data = argv[1];
460 	key.size = sizeof(recno_t);
461 	data.data = argv[2];
462 	data.size = strlen(data.data);
463 	status = (db->put)(db, &key, &data, R_IBEFORE);
464 	switch (status) {
465 	case RET_ERROR:
466 		perror("ibefore/put");
467 		break;
468 	case RET_SPECIAL:
469 		(void)printf("%s (duplicate key)\n", argv[1]);
470 		break;
471 	case RET_SUCCESS:
472 		break;
473 	}
474 }
475 
476 void
477 icursor(db, argv)
478 	DB *db;
479 	char **argv;
480 {
481 	int status;
482 	DBT data, key;
483 
484 	key.data = argv[1];
485 	if (recno)
486 		key.size = sizeof(recno_t);
487 	else
488 		key.size = strlen(argv[1]) + 1;
489 	data.data = argv[2];
490 	data.size = strlen(argv[2]) + 1;
491 
492 	status = (*db->put)(db, &key, &data, R_CURSOR);
493 	switch (status) {
494 	case RET_ERROR:
495 		perror("icursor/put");
496 		break;
497 	case RET_SPECIAL:
498 		(void)printf("%s (duplicate key)\n", argv[1]);
499 		break;
500 	case RET_SUCCESS:
501 		break;
502 	}
503 }
504 
505 void
506 insert(db, argv)
507 	DB *db;
508 	char **argv;
509 {
510 	int status;
511 	DBT data, key;
512 
513 	key.data = argv[1];
514 	if (recno)
515 		key.size = sizeof(recno_t);
516 	else
517 		key.size = strlen(argv[1]) + 1;
518 	data.data = argv[2];
519 	data.size = strlen(argv[2]) + 1;
520 
521 	status = (*db->put)(db, &key, &data, R_NOOVERWRITE);
522 	switch (status) {
523 	case RET_ERROR:
524 		perror("insert/put");
525 		break;
526 	case RET_SPECIAL:
527 		(void)printf("%s (duplicate key)\n", argv[1]);
528 		break;
529 	case RET_SUCCESS:
530 		break;
531 	}
532 }
533 
534 void
535 last(db, argv)
536 	DB *db;
537 	char **argv;
538 {
539 	DBT data, key;
540 	int status;
541 
542 	status = (*db->seq)(db, &key, &data, R_LAST);
543 
544 	switch (status) {
545 	case RET_ERROR:
546 		perror("last/seq");
547 		break;
548 	case RET_SPECIAL:
549 		(void)printf("no more keys\n");
550 		break;
551 	case RET_SUCCESS:
552 		keydata(&key, &data);
553 		break;
554 	}
555 }
556 
557 void
558 list(db, argv)
559 	DB *db;
560 	char **argv;
561 {
562 	DBT data, key;
563 	FILE *fp;
564 	int status;
565 
566 	if ((fp = fopen(argv[1], "w")) == NULL) {
567 		(void)fprintf(stderr, "%s: %s\n", argv[1], strerror(errno));
568 		return;
569 	}
570 	status = (*db->seq)(db, &key, &data, R_FIRST);
571 	while (status == RET_SUCCESS) {
572 		(void)fprintf(fp, "%s\n", key.data);
573 		status = (*db->seq)(db, &key, &data, R_NEXT);
574 	}
575 	if (status == RET_ERROR)
576 		perror("list/seq");
577 }
578 
579 DB *BUGdb;
580 void
581 load(db, argv)
582 	DB *db;
583 	char **argv;
584 {
585 	register char *p, *t;
586 	FILE *fp;
587 	DBT data, key;
588 	recno_t cnt;
589 	size_t len;
590 	int status;
591 	char *lp, buf[16 * 1024];
592 
593 	BUGdb = db;
594 	if ((fp = fopen(argv[1], "r")) == NULL) {
595 		(void)fprintf(stderr, "%s: %s\n", argv[1], strerror(errno));
596 		return;
597 	}
598 	(void)printf("loading %s...\n", argv[1]);
599 
600 	for (cnt = 1; (lp = fgetline(fp, &len)) != NULL; ++cnt) {
601 		if (recno) {
602 			key.data = &cnt;
603 			key.size = sizeof(recno_t);
604 			data.data = lp;
605 			data.size = len + 1;
606 		} else {
607 			key.data = lp;
608 			key.size = len + 1;
609 			for (p = lp + len - 1, t = buf; p >= lp; *t++ = *p--);
610 			*t = '\0';
611 			data.data = buf;
612 			data.size = len + 1;
613 		}
614 
615 		status = (*db->put)(db, &key, &data, R_NOOVERWRITE);
616 		switch (status) {
617 		case RET_ERROR:
618 			perror("load/put");
619 			exit(1);
620 		case RET_SPECIAL:
621 			if (recno)
622 				(void)fprintf(stderr,
623 				    "duplicate: %ld {%s}\n", cnt, data.data);
624 			else
625 				(void)fprintf(stderr,
626 				    "duplicate: %ld {%s}\n", cnt, key.data);
627 			exit(1);
628 		case RET_SUCCESS:
629 			break;
630 		}
631 	}
632 	(void)fclose(fp);
633 }
634 
635 void
636 next(db, argv)
637 	DB *db;
638 	char **argv;
639 {
640 	DBT data, key;
641 	int status;
642 
643 	status = (*db->seq)(db, &key, &data, R_NEXT);
644 
645 	switch (status) {
646 	case RET_ERROR:
647 		perror("next/seq");
648 		break;
649 	case RET_SPECIAL:
650 		(void)printf("no more keys\n");
651 		break;
652 	case RET_SUCCESS:
653 		keydata(&key, &data);
654 		break;
655 	}
656 }
657 
658 void
659 previous(db, argv)
660 	DB *db;
661 	char **argv;
662 {
663 	DBT data, key;
664 	int status;
665 
666 	status = (*db->seq)(db, &key, &data, R_PREV);
667 
668 	switch (status) {
669 	case RET_ERROR:
670 		perror("previous/seq");
671 		break;
672 	case RET_SPECIAL:
673 		(void)printf("no more keys\n");
674 		break;
675 	case RET_SUCCESS:
676 		keydata(&key, &data);
677 		break;
678 	}
679 }
680 
681 void
682 show(db, argv)
683 	DB *db;
684 	char **argv;
685 {
686 	BTREE *t;
687 	PAGE *h;
688 	pgno_t pg;
689 
690 	pg = atoi(argv[1]);
691 	t = db->internal;
692 	if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL) {
693 		(void)printf("getpage of %ld failed\n", pg);
694 		return;
695 	}
696 	if (pg == 0)
697 		__bt_dmpage(h);
698 	else
699 		__bt_dpage(h);
700 	mpool_put(t->bt_mp, h, 0);
701 }
702 
703 void
704 bstat(db, argv)
705 	DB *db;
706 	char **argv;
707 {
708 	(void)printf("BTREE\n");
709 	__bt_stat(db);
710 }
711 
712 void
713 mstat(db, argv)
714 	DB *db;
715 	char **argv;
716 {
717 	(void)printf("MPOOL\n");
718 	mpool_stat(((BTREE *)db->internal)->bt_mp);
719 }
720 
721 void
722 keydata(key, data)
723 	DBT *key, *data;
724 {
725 	if (!recno && key->size > 0)
726 		(void)printf("%s/", key->data);
727 	if (data->size > 0)
728 		(void)printf("%s", data->data);
729 	(void)printf("\n");
730 }
731 
732 void
733 usage()
734 {
735 	(void)fprintf(stderr,
736 	    "usage: %s [-bdlu] [-c cache] [-i file] [-p page] [file]\n",
737 	    progname);
738 	exit (1);
739 }
740