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 fclose(fp); 567 } 568 569 DB *BUGdb; 570 void 571 load(DB *db, char **argv) 572 { 573 char *p, *t; 574 FILE *fp; 575 DBT data, key; 576 recno_t cnt; 577 size_t len; 578 int status; 579 char *lp, buf[16 * 1024]; 580 581 BUGdb = db; 582 if ((fp = fopen(argv[1], "r")) == NULL) { 583 fprintf(stderr, "%s: %s\n", argv[1], strerror(errno)); 584 return; 585 } 586 printf("loading %s...\n", argv[1]); 587 588 for (cnt = 1; (lp = fgetline(fp, &len)) != NULL; ++cnt) { 589 if (recno) { 590 key.data = &cnt; 591 key.size = sizeof(recno_t); 592 data.data = lp; 593 data.size = len + 1; 594 } else { 595 key.data = lp; 596 key.size = len + 1; 597 for (p = lp + len - 1, t = buf; p >= lp; *t++ = *p--); 598 *t = '\0'; 599 data.data = buf; 600 data.size = len + 1; 601 } 602 603 status = (*db->put)(db, &key, &data, R_NOOVERWRITE); 604 switch (status) { 605 case RET_ERROR: 606 perror("load/put"); 607 exit(1); 608 case RET_SPECIAL: 609 if (recno) 610 fprintf(stderr, 611 "duplicate: %ld {%s}\n", cnt, data.data); 612 else 613 fprintf(stderr, 614 "duplicate: %ld {%s}\n", cnt, key.data); 615 exit(1); 616 case RET_SUCCESS: 617 break; 618 } 619 } 620 fclose(fp); 621 } 622 623 void 624 next(DB *db, char **argv) 625 { 626 DBT data, key; 627 int status; 628 629 status = (*db->seq)(db, &key, &data, R_NEXT); 630 631 switch (status) { 632 case RET_ERROR: 633 perror("next/seq"); 634 break; 635 case RET_SPECIAL: 636 printf("no more keys\n"); 637 break; 638 case RET_SUCCESS: 639 keydata(&key, &data); 640 break; 641 } 642 } 643 644 void 645 previous(DB *db, char **argv) 646 { 647 DBT data, key; 648 int status; 649 650 status = (*db->seq)(db, &key, &data, R_PREV); 651 652 switch (status) { 653 case RET_ERROR: 654 perror("previous/seq"); 655 break; 656 case RET_SPECIAL: 657 printf("no more keys\n"); 658 break; 659 case RET_SUCCESS: 660 keydata(&key, &data); 661 break; 662 } 663 } 664 665 void 666 show(DB *db, char **argv) 667 { 668 BTREE *t; 669 PAGE *h; 670 pgno_t pg; 671 672 pg = atoi(argv[1]); 673 t = db->internal; 674 if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL) { 675 printf("getpage of %ld failed\n", pg); 676 return; 677 } 678 if (pg == 0) 679 __bt_dmpage(h); 680 else 681 __bt_dpage(h); 682 mpool_put(t->bt_mp, h, 0); 683 } 684 685 void 686 bstat(DB *db, char **argv) 687 { 688 printf("BTREE\n"); 689 __bt_stat(db); 690 } 691 692 void 693 mstat(DB *db, char **argv) 694 { 695 printf("MPOOL\n"); 696 mpool_stat(((BTREE *)db->internal)->bt_mp); 697 } 698 699 void 700 keydata(DBT *key, DBT *data) 701 { 702 if (!recno && key->size > 0) 703 printf("%s/", key->data); 704 if (data->size > 0) 705 printf("%s", data->data); 706 printf("\n"); 707 } 708 709 void 710 usage(void) 711 { 712 fprintf(stderr, 713 "usage: %s [-bdlu] [-c cache] [-i file] [-p page] [file]\n", 714 progname); 715 exit (1); 716 } 717