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