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