xref: /original-bsd/lib/libc/db/test/btree.tests/main.c (revision 155be1a3)
1 /*-
2  * Copyright (c) 1990 The Regents of the University of California.
3  * 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	5.3 (Berkeley) 09/12/91";
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, 1, 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 void
580 load(db, argv)
581 	DB *db;
582 	char **argv;
583 {
584 	register char *p, *t;
585 	FILE *fp;
586 	DBT data, key;
587 	int status;
588 	char b1[256], b2[256];
589 
590 	if ((fp = fopen(argv[1], "r")) == NULL) {
591 		perror(argv[1]);
592 		return;
593 	}
594 	(void)printf("loading %s...\n", dict);
595 
596 	key.data = b1;
597 	data.data = b2;
598 	while (fgets(b1, sizeof(b1), fp) != NULL) {
599 		data.size = strlen(b1);
600 		b1[data.size - 1] = '\0';
601 		for (p = &b1[data.size - 2], t = b2; p >= b1; *t++ = *p--);
602 		b2[data.size - 1] = '\0';
603 		key.size = data.size;
604 
605 		status = (*db->put)(db, &key, &data, R_NOOVERWRITE);
606 		switch (status) {
607 		case RET_ERROR:
608 			perror("load/put");
609 			exit(1);
610 		case RET_SPECIAL:
611 			(void)fprintf(stderr, "duplicate: %s\n", key.data);
612 			exit(1);
613 		case RET_SUCCESS:
614 			break;
615 		}
616 	}
617 	(void)fclose(fp);
618 }
619 
620 void
621 next(db, argv)
622 	DB *db;
623 	char **argv;
624 {
625 	DBT data, key;
626 	int status;
627 
628 	status = (*db->seq)(db, &key, &data, R_NEXT);
629 
630 	switch (status) {
631 	case RET_ERROR:
632 		perror("next/seq");
633 		break;
634 	case RET_SPECIAL:
635 		(void)printf("no more keys\n");
636 		break;
637 	case RET_SUCCESS:
638 		keydata(&key, &data);
639 		break;
640 	}
641 }
642 
643 void
644 previous(db, argv)
645 	DB *db;
646 	char **argv;
647 {
648 	DBT data, key;
649 	int status;
650 
651 	status = (*db->seq)(db, &key, &data, R_PREV);
652 
653 	switch (status) {
654 	case RET_ERROR:
655 		perror("previous/seq");
656 		break;
657 	case RET_SPECIAL:
658 		(void)printf("no more keys\n");
659 		break;
660 	case RET_SUCCESS:
661 		keydata(&key, &data);
662 		break;
663 	}
664 }
665 
666 void
667 show(db, argv)
668 	DB *db;
669 	char **argv;
670 {
671 	BTREE *t;
672 	PAGE *h;
673 	pgno_t pg;
674 
675 	pg = atoi(argv[1]);
676 	t = db->internal;
677 	if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL) {
678 		(void)printf("getpage of %ld failed\n", pg);
679 		return;
680 	}
681 	if (pg == 0)
682 		__bt_dmpage(h);
683 	else
684 		__bt_dpage(h);
685 	mpool_put(t->bt_mp, h, 0);
686 }
687 
688 void
689 bstat(db, argv)
690 	DB *db;
691 	char **argv;
692 {
693 	(void)printf("BTREE\n");
694 	__bt_stat(db);
695 }
696 
697 void
698 mstat(db, argv)
699 	DB *db;
700 	char **argv;
701 {
702 	(void)printf("MPOOL\n");
703 	mpool_stat(((BTREE *)db->internal)->bt_mp);
704 }
705 
706 void
707 keydata(key, data)
708 	DBT *key, *data;
709 {
710 	if (!recno && key->size > 0)
711 		(void)printf("%s/", key->data);
712 	if (data->size > 0)
713 		(void)printf("%s", data->data);
714 	(void)printf("\n");
715 }
716 
717 void
718 usage()
719 {
720 	(void)fprintf(stderr,
721 	    "usage: %s [-bdlu] [-c cache] [-i file] [-p page] [file]\n",
722 	    progname);
723 	exit (1);
724 }
725