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