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