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 * $FreeBSD: head/lib/libc/db/test/btree.tests/main.c 176380 2008-02-18 03:19:25Z kevlo $ 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(int argc, char **argv) 115 { 116 int c; 117 DB *db; 118 BTREEINFO b; 119 120 progname = *argv; 121 122 b.flags = 0; 123 b.cachesize = 0; 124 b.maxkeypage = 0; 125 b.minkeypage = 0; 126 b.psize = 0; 127 b.compare = NULL; 128 b.prefix = NULL; 129 b.lorder = 0; 130 131 while ((c = getopt(argc, argv, "bc:di:lp:ru")) != -1) { 132 switch (c) { 133 case 'b': 134 b.lorder = BIG_ENDIAN; 135 break; 136 case 'c': 137 b.cachesize = atoi(optarg); 138 break; 139 case 'd': 140 b.flags |= R_DUP; 141 break; 142 case 'i': 143 dict = optarg; 144 break; 145 case 'l': 146 b.lorder = LITTLE_ENDIAN; 147 break; 148 case 'p': 149 b.psize = atoi(optarg); 150 break; 151 case 'r': 152 recno = 1; 153 break; 154 case 'u': 155 b.flags = 0; 156 break; 157 default: 158 usage(); 159 } 160 } 161 argc -= optind; 162 argv += optind; 163 164 if (recno) 165 db = dbopen(*argv == NULL ? NULL : *argv, O_RDWR, 166 0, DB_RECNO, NULL); 167 else 168 db = dbopen(*argv == NULL ? NULL : *argv, O_CREAT|O_RDWR, 169 0600, DB_BTREE, &b); 170 171 if (db == NULL) { 172 fprintf(stderr, "dbopen: %s\n", strerror(errno)); 173 exit(1); 174 } 175 globaldb = db; 176 user(db); 177 exit(0); 178 /* NOTREACHED */ 179 } 180 181 void 182 user(DB *db) 183 { 184 FILE *ifp; 185 int argc, i, last; 186 char *lbuf, *argv[4], buf[512]; 187 188 if ((ifp = fopen("/dev/tty", "r")) == NULL) { 189 fprintf(stderr, 190 "/dev/tty: %s\n", strerror(errno)); 191 exit(1); 192 } 193 for (last = 0;;) { 194 printf("> "); 195 fflush(stdout); 196 if ((lbuf = fgets(&buf[0], 512, ifp)) == NULL) 197 break; 198 if (lbuf[0] == '\n') { 199 i = last; 200 goto uselast; 201 } 202 lbuf[strlen(lbuf) - 1] = '\0'; 203 204 if (lbuf[0] == 'q') 205 break; 206 207 argc = parse(lbuf, &argv[0], 3); 208 if (argc == 0) 209 continue; 210 211 for (i = 0; commands[i].cmd != NULL; i++) 212 if (strncmp(commands[i].cmd, argv[0], 213 strlen(commands[i].cmd)) == 0) 214 break; 215 216 if (commands[i].cmd == NULL) { 217 fprintf(stderr, 218 "%s: command unknown ('help' for help)\n", lbuf); 219 continue; 220 } 221 222 if (commands[i].nargs != argc - 1) { 223 fprintf(stderr, "usage: %s\n", commands[i].usage); 224 continue; 225 } 226 227 if (recno && commands[i].rconv) { 228 static recno_t nlong; 229 nlong = atoi(argv[1]); 230 argv[1] = (char *)&nlong; 231 } 232 uselast: last = i; 233 (*commands[i].func)(db, argv); 234 } 235 if ((db->sync)(db) == RET_ERROR) 236 perror("dbsync"); 237 else if ((db->close)(db) == RET_ERROR) 238 perror("dbclose"); 239 } 240 241 int 242 parse(char *lbuf, char **argv, int maxargc) 243 { 244 int argc = 0; 245 char *c; 246 247 c = lbuf; 248 while (isspace(*c)) 249 c++; 250 while (*c != '\0' && argc < maxargc) { 251 *argv++ = c; 252 argc++; 253 while (!isspace(*c) && *c != '\0') { 254 c++; 255 } 256 while (isspace(*c)) 257 *c++ = '\0'; 258 } 259 return (argc); 260 } 261 262 void 263 append(DB *db, char **argv) 264 { 265 DBT key, data; 266 int status; 267 268 if (!recno) { 269 fprintf(stderr, 270 "append only available for recno db's.\n"); 271 return; 272 } 273 key.data = argv[1]; 274 key.size = sizeof(recno_t); 275 data.data = argv[2]; 276 data.size = strlen(data.data); 277 status = (db->put)(db, &key, &data, R_APPEND); 278 switch (status) { 279 case RET_ERROR: 280 perror("append/put"); 281 break; 282 case RET_SPECIAL: 283 printf("%s (duplicate key)\n", argv[1]); 284 break; 285 case RET_SUCCESS: 286 break; 287 } 288 } 289 290 void 291 cursor(DB *db, char **argv) 292 { 293 DBT data, key; 294 int status; 295 296 key.data = argv[1]; 297 if (recno) 298 key.size = sizeof(recno_t); 299 else 300 key.size = strlen(argv[1]) + 1; 301 status = (*db->seq)(db, &key, &data, R_CURSOR); 302 switch (status) { 303 case RET_ERROR: 304 perror("cursor/seq"); 305 break; 306 case RET_SPECIAL: 307 printf("key not found\n"); 308 break; 309 case RET_SUCCESS: 310 keydata(&key, &data); 311 break; 312 } 313 } 314 315 void 316 delcur(DB *db, char **argv) 317 { 318 int status; 319 320 status = (*db->del)(db, NULL, R_CURSOR); 321 322 if (status == RET_ERROR) 323 perror("delcur/del"); 324 } 325 326 void 327 delete(DB *db, char **argv) 328 { 329 DBT key; 330 int status; 331 332 key.data = argv[1]; 333 if (recno) 334 key.size = sizeof(recno_t); 335 else 336 key.size = strlen(argv[1]) + 1; 337 338 status = (*db->del)(db, &key, 0); 339 switch (status) { 340 case RET_ERROR: 341 perror("delete/del"); 342 break; 343 case RET_SPECIAL: 344 printf("key not found\n"); 345 break; 346 case RET_SUCCESS: 347 break; 348 } 349 } 350 351 void 352 dump(DB *db, char **argv) 353 { 354 __bt_dump(db); 355 } 356 357 void 358 first(DB *db, char **argv) 359 { 360 DBT data, key; 361 int status; 362 363 status = (*db->seq)(db, &key, &data, R_FIRST); 364 365 switch (status) { 366 case RET_ERROR: 367 perror("first/seq"); 368 break; 369 case RET_SPECIAL: 370 printf("no more keys\n"); 371 break; 372 case RET_SUCCESS: 373 keydata(&key, &data); 374 break; 375 } 376 } 377 378 void 379 get(DB *db, char **argv) 380 { 381 DBT data, key; 382 int status; 383 384 key.data = argv[1]; 385 if (recno) 386 key.size = sizeof(recno_t); 387 else 388 key.size = strlen(argv[1]) + 1; 389 390 status = (*db->get)(db, &key, &data, 0); 391 392 switch (status) { 393 case RET_ERROR: 394 perror("get/get"); 395 break; 396 case RET_SPECIAL: 397 printf("key not found\n"); 398 break; 399 case RET_SUCCESS: 400 keydata(&key, &data); 401 break; 402 } 403 } 404 405 void 406 help(DB *db, char **argv) 407 { 408 int i; 409 410 for (i = 0; commands[i].cmd; i++) 411 if (commands[i].descrip) 412 printf("%s: %s\n", 413 commands[i].usage, commands[i].descrip); 414 } 415 416 void 417 iafter(DB *db, char **argv) 418 { 419 DBT key, data; 420 int status; 421 422 if (!recno) { 423 fprintf(stderr, 424 "iafter only available for recno db's.\n"); 425 return; 426 } 427 key.data = argv[1]; 428 key.size = sizeof(recno_t); 429 data.data = argv[2]; 430 data.size = strlen(data.data); 431 status = (db->put)(db, &key, &data, R_IAFTER); 432 switch (status) { 433 case RET_ERROR: 434 perror("iafter/put"); 435 break; 436 case RET_SPECIAL: 437 printf("%s (duplicate key)\n", argv[1]); 438 break; 439 case RET_SUCCESS: 440 break; 441 } 442 } 443 444 void 445 ibefore(DB *db, char **argv) 446 { 447 DBT key, data; 448 int status; 449 450 if (!recno) { 451 fprintf(stderr, 452 "ibefore 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_IBEFORE); 460 switch (status) { 461 case RET_ERROR: 462 perror("ibefore/put"); 463 break; 464 case RET_SPECIAL: 465 printf("%s (duplicate key)\n", argv[1]); 466 break; 467 case RET_SUCCESS: 468 break; 469 } 470 } 471 472 void 473 icursor(DB *db, char **argv) 474 { 475 int status; 476 DBT data, key; 477 478 key.data = argv[1]; 479 if (recno) 480 key.size = sizeof(recno_t); 481 else 482 key.size = strlen(argv[1]) + 1; 483 data.data = argv[2]; 484 data.size = strlen(argv[2]) + 1; 485 486 status = (*db->put)(db, &key, &data, R_CURSOR); 487 switch (status) { 488 case RET_ERROR: 489 perror("icursor/put"); 490 break; 491 case RET_SPECIAL: 492 printf("%s (duplicate key)\n", argv[1]); 493 break; 494 case RET_SUCCESS: 495 break; 496 } 497 } 498 499 void 500 insert(DB *db, 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_NOOVERWRITE); 514 switch (status) { 515 case RET_ERROR: 516 perror("insert/put"); 517 break; 518 case RET_SPECIAL: 519 printf("%s (duplicate key)\n", argv[1]); 520 break; 521 case RET_SUCCESS: 522 break; 523 } 524 } 525 526 void 527 last(DB *db, char **argv) 528 { 529 DBT data, key; 530 int status; 531 532 status = (*db->seq)(db, &key, &data, R_LAST); 533 534 switch (status) { 535 case RET_ERROR: 536 perror("last/seq"); 537 break; 538 case RET_SPECIAL: 539 printf("no more keys\n"); 540 break; 541 case RET_SUCCESS: 542 keydata(&key, &data); 543 break; 544 } 545 } 546 547 void 548 list(DB *db, char **argv) 549 { 550 DBT data, key; 551 FILE *fp; 552 int status; 553 554 if ((fp = fopen(argv[1], "w")) == NULL) { 555 fprintf(stderr, "%s: %s\n", argv[1], strerror(errno)); 556 return; 557 } 558 status = (*db->seq)(db, &key, &data, R_FIRST); 559 while (status == RET_SUCCESS) { 560 fprintf(fp, "%s\n", key.data); 561 status = (*db->seq)(db, &key, &data, R_NEXT); 562 } 563 if (status == RET_ERROR) 564 perror("list/seq"); 565 } 566 567 DB *BUGdb; 568 void 569 load(DB *db, char **argv) 570 { 571 char *p, *t; 572 FILE *fp; 573 DBT data, key; 574 recno_t cnt; 575 size_t len; 576 int status; 577 char *lp, buf[16 * 1024]; 578 579 BUGdb = db; 580 if ((fp = fopen(argv[1], "r")) == NULL) { 581 fprintf(stderr, "%s: %s\n", argv[1], strerror(errno)); 582 return; 583 } 584 printf("loading %s...\n", argv[1]); 585 586 for (cnt = 1; (lp = fgetline(fp, &len)) != NULL; ++cnt) { 587 if (recno) { 588 key.data = &cnt; 589 key.size = sizeof(recno_t); 590 data.data = lp; 591 data.size = len + 1; 592 } else { 593 key.data = lp; 594 key.size = len + 1; 595 for (p = lp + len - 1, t = buf; p >= lp; *t++ = *p--); 596 *t = '\0'; 597 data.data = buf; 598 data.size = len + 1; 599 } 600 601 status = (*db->put)(db, &key, &data, R_NOOVERWRITE); 602 switch (status) { 603 case RET_ERROR: 604 perror("load/put"); 605 exit(1); 606 case RET_SPECIAL: 607 if (recno) 608 fprintf(stderr, 609 "duplicate: %ld {%s}\n", cnt, data.data); 610 else 611 fprintf(stderr, 612 "duplicate: %ld {%s}\n", cnt, key.data); 613 exit(1); 614 case RET_SUCCESS: 615 break; 616 } 617 } 618 fclose(fp); 619 } 620 621 void 622 next(DB *db, char **argv) 623 { 624 DBT data, key; 625 int status; 626 627 status = (*db->seq)(db, &key, &data, R_NEXT); 628 629 switch (status) { 630 case RET_ERROR: 631 perror("next/seq"); 632 break; 633 case RET_SPECIAL: 634 printf("no more keys\n"); 635 break; 636 case RET_SUCCESS: 637 keydata(&key, &data); 638 break; 639 } 640 } 641 642 void 643 previous(DB *db, char **argv) 644 { 645 DBT data, key; 646 int status; 647 648 status = (*db->seq)(db, &key, &data, R_PREV); 649 650 switch (status) { 651 case RET_ERROR: 652 perror("previous/seq"); 653 break; 654 case RET_SPECIAL: 655 printf("no more keys\n"); 656 break; 657 case RET_SUCCESS: 658 keydata(&key, &data); 659 break; 660 } 661 } 662 663 void 664 show(DB *db, char **argv) 665 { 666 BTREE *t; 667 PAGE *h; 668 pgno_t pg; 669 670 pg = atoi(argv[1]); 671 t = db->internal; 672 if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL) { 673 printf("getpage of %ld failed\n", pg); 674 return; 675 } 676 if (pg == 0) 677 __bt_dmpage(h); 678 else 679 __bt_dpage(h); 680 mpool_put(t->bt_mp, h, 0); 681 } 682 683 void 684 bstat(DB *db, char **argv) 685 { 686 printf("BTREE\n"); 687 __bt_stat(db); 688 } 689 690 void 691 mstat(DB *db, char **argv) 692 { 693 printf("MPOOL\n"); 694 mpool_stat(((BTREE *)db->internal)->bt_mp); 695 } 696 697 void 698 keydata(DBT *key, DBT *data) 699 { 700 if (!recno && key->size > 0) 701 printf("%s/", key->data); 702 if (data->size > 0) 703 printf("%s", data->data); 704 printf("\n"); 705 } 706 707 void 708 usage(void) 709 { 710 fprintf(stderr, 711 "usage: %s [-bdlu] [-c cache] [-i file] [-p page] [file]\n", 712 progname); 713 exit (1); 714 } 715