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