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 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) __P((DB *, char **)); 56 char *usage, *descrip; 57 } cmd_table; 58 59 int stopstop; 60 DB *globaldb; 61 62 void append __P((DB *, char **)); 63 void bstat __P((DB *, char **)); 64 void cursor __P((DB *, char **)); 65 void delcur __P((DB *, char **)); 66 void delete __P((DB *, char **)); 67 void dump __P((DB *, char **)); 68 void first __P((DB *, char **)); 69 void get __P((DB *, char **)); 70 void help __P((DB *, char **)); 71 void iafter __P((DB *, char **)); 72 void ibefore __P((DB *, char **)); 73 void icursor __P((DB *, char **)); 74 void insert __P((DB *, char **)); 75 void keydata __P((DBT *, DBT *)); 76 void last __P((DB *, char **)); 77 void list __P((DB *, char **)); 78 void load __P((DB *, char **)); 79 void mstat __P((DB *, char **)); 80 void next __P((DB *, char **)); 81 int parse __P((char *, char **, int)); 82 void previous __P((DB *, char **)); 83 void show __P((DB *, char **)); 84 void usage __P((void)); 85 void user __P((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 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")) != EOF) { 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 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 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 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 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 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 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 370 dump(db, argv) 371 DB *db; 372 char **argv; 373 { 374 __bt_dump(db); 375 } 376 377 void 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 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 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 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 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 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 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 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 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 607 load(db, argv) 608 DB *db; 609 char **argv; 610 { 611 register 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 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 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 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 730 bstat(db, argv) 731 DB *db; 732 char **argv; 733 { 734 (void)printf("BTREE\n"); 735 __bt_stat(db); 736 } 737 738 void 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 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 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