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