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