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