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 * 3. 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)
36 static 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$");
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
51 typedef 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
59 int stopstop;
60 DB *globaldb;
61
62 void append(DB *, char **);
63 void bstat(DB *, char **);
64 void cursor(DB *, char **);
65 void delcur(DB *, char **);
66 void delete(DB *, char **);
67 void dump(DB *, char **);
68 void first(DB *, char **);
69 void get(DB *, char **);
70 void help(DB *, char **);
71 void iafter(DB *, char **);
72 void ibefore(DB *, char **);
73 void icursor(DB *, char **);
74 void insert(DB *, char **);
75 void keydata(DBT *, DBT *);
76 void last(DB *, char **);
77 void list(DB *, char **);
78 void load(DB *, char **);
79 void mstat(DB *, char **);
80 void next(DB *, char **);
81 int parse(char *, char **, int);
82 void previous(DB *, char **);
83 void show(DB *, char **);
84 void usage(void);
85 void user(DB *);
86
87 cmd_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
114 int recno; /* use record numbers */
115 char *dict = "words"; /* default dictionary */
116 char *progname;
117
118 int
main(argc,argv)119 main(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
188 void
user(db)189 user(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 }
240 uselast: 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
249 int
parse(lbuf,argv,maxargc)250 parse(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
272 void
append(db,argv)273 append(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
302 void
cursor(db,argv)303 cursor(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
329 void
delcur(db,argv)330 delcur(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
342 void
delete(db,argv)343 delete(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
369 void
dump(db,argv)370 dump(db, argv)
371 DB *db;
372 char **argv;
373 {
374 __bt_dump(db);
375 }
376
377 void
first(db,argv)378 first(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
400 void
get(db,argv)401 get(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
429 void
help(db,argv)430 help(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
442 void
iafter(db,argv)443 iafter(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
472 void
ibefore(db,argv)473 ibefore(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
502 void
icursor(db,argv)503 icursor(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
531 void
insert(db,argv)532 insert(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
560 void
last(db,argv)561 last(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
583 void
list(db,argv)584 list(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
605 DB *BUGdb;
606 void
load(db,argv)607 load(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
661 void
next(db,argv)662 next(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
684 void
previous(db,argv)685 previous(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
707 void
show(db,argv)708 show(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
729 void
bstat(db,argv)730 bstat(db, argv)
731 DB *db;
732 char **argv;
733 {
734 (void)printf("BTREE\n");
735 __bt_stat(db);
736 }
737
738 void
mstat(db,argv)739 mstat(db, argv)
740 DB *db;
741 char **argv;
742 {
743 (void)printf("MPOOL\n");
744 mpool_stat(((BTREE *)db->internal)->bt_mp);
745 }
746
747 void
keydata(key,data)748 keydata(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
758 void
usage()759 usage()
760 {
761 (void)fprintf(stderr,
762 "usage: %s [-bdlu] [-c cache] [-i file] [-p page] [file]\n",
763 progname);
764 exit (1);
765 }
766