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) 34 static 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$"); 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 49 typedef 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 57 int stopstop; 58 DB *globaldb; 59 60 void append(DB *, char **); 61 void bstat(DB *, char **); 62 void cursor(DB *, char **); 63 void delcur(DB *, char **); 64 void delete(DB *, char **); 65 void dump(DB *, char **); 66 void first(DB *, char **); 67 void get(DB *, char **); 68 void help(DB *, char **); 69 void iafter(DB *, char **); 70 void ibefore(DB *, char **); 71 void icursor(DB *, char **); 72 void insert(DB *, char **); 73 void keydata(DBT *, DBT *); 74 void last(DB *, char **); 75 void list(DB *, char **); 76 void load(DB *, char **); 77 void mstat(DB *, char **); 78 void next(DB *, char **); 79 int parse(char *, char **, int); 80 void previous(DB *, char **); 81 void show(DB *, char **); 82 void usage(void); 83 void user(DB *); 84 85 cmd_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 112 int recno; /* use record numbers */ 113 char *dict = "words"; /* default dictionary */ 114 char *progname; 115 116 int 117 main(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")) != EOF) { 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 186 void 187 user(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 } 238 uselast: 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 247 int 248 parse(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 270 void 271 append(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 300 void 301 cursor(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 327 void 328 delcur(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 340 void 341 delete(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 367 void 368 dump(db, argv) 369 DB *db; 370 char **argv; 371 { 372 __bt_dump(db); 373 } 374 375 void 376 first(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 398 void 399 get(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 427 void 428 help(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 440 void 441 iafter(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 470 void 471 ibefore(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 500 void 501 icursor(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 529 void 530 insert(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 558 void 559 last(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 581 void 582 list(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 603 DB *BUGdb; 604 void 605 load(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 659 void 660 next(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 682 void 683 previous(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 705 void 706 show(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 727 void 728 bstat(db, argv) 729 DB *db; 730 char **argv; 731 { 732 (void)printf("BTREE\n"); 733 __bt_stat(db); 734 } 735 736 void 737 mstat(db, argv) 738 DB *db; 739 char **argv; 740 { 741 (void)printf("MPOOL\n"); 742 mpool_stat(((BTREE *)db->internal)->bt_mp); 743 } 744 745 void 746 keydata(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 756 void 757 usage() 758 { 759 (void)fprintf(stderr, 760 "usage: %s [-bdlu] [-c cache] [-i file] [-p page] [file]\n", 761 progname); 762 exit (1); 763 } 764