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