| Commit | Line | Data |
|---|---|---|
| 984263bc MD |
1 | /*- |
| 2 | * Copyright (c) 1992, 1993, 1994 | |
| 3 | * The Regents of the University of California. All rights reserved. | |
| 4 | * | |
| 5 | * Redistribution and use in source and binary forms, with or without | |
| 6 | * modification, are permitted provided that the following conditions | |
| 7 | * are met: | |
| 8 | * 1. Redistributions of source code must retain the above copyright | |
| 9 | * notice, this list of conditions and the following disclaimer. | |
| 10 | * 2. Redistributions in binary form must reproduce the above copyright | |
| 11 | * notice, this list of conditions and the following disclaimer in the | |
| 12 | * documentation and/or other materials provided with the distribution. | |
| cbebfd39 | 13 | * 3. Neither the name of the University nor the names of its contributors |
| 984263bc MD |
14 | * may be used to endorse or promote products derived from this software |
| 15 | * without specific prior written permission. | |
| 16 | * | |
| 17 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
| 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
| 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
| 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| 25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
| 26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 27 | * SUCH DAMAGE. | |
| 1de703da MD |
28 | * |
| 29 | * @(#) Copyright (c) 1992, 1993, 1994 The Regents of the University of California. All rights reserved. | |
| 30 | * @(#)dbtest.c 8.17 (Berkeley) 9/1/94 | |
| 31 | * $FreeBSD: src/lib/libc/db/test/dbtest.c,v 1.3.8.1 2000/08/21 22:44:47 jhb Exp $ | |
| 9b0ec895 | 32 | * $DragonFly: src/lib/libc/db/test/dbtest.c,v 1.8 2008/07/10 18:29:51 swildner Exp $ |
| 984263bc MD |
33 | */ |
| 34 | ||
| 984263bc MD |
35 | #include <sys/param.h> |
| 36 | #include <sys/stat.h> | |
| 37 | ||
| 38 | #include <ctype.h> | |
| 39 | #include <errno.h> | |
| 40 | #include <fcntl.h> | |
| 41 | #include <limits.h> | |
| 42 | #include <stdio.h> | |
| 43 | #include <stdlib.h> | |
| 44 | #include <string.h> | |
| 45 | #include <unistd.h> | |
| 46 | ||
| 47 | #include <db.h> | |
| 48 | ||
| 49 | enum S { COMMAND, COMPARE, GET, PUT, REMOVE, SEQ, SEQFLAG, KEY, DATA }; | |
| 50 | ||
| 064e1fb3 EN |
51 | void compare (DBT *, DBT *); |
| 52 | DBTYPE dbtype (char *); | |
| 53 | void dump (DB *, int); | |
| 53242694 | 54 | void err (const char *, ...) __printflike(1, 2); |
| 064e1fb3 EN |
55 | void get (DB *, DBT *); |
| 56 | void getdata (DB *, DBT *, DBT *); | |
| 57 | void put (DB *, DBT *, DBT *); | |
| 58 | void rem (DB *, DBT *); | |
| 59 | char *sflags (int); | |
| 60 | void synk (DB *); | |
| 61 | void *rfile (char *, size_t *); | |
| 62 | void seq (DB *, DBT *); | |
| 63 | u_int setflags (char *); | |
| 64 | void *setinfo (DBTYPE, char *); | |
| 65 | void usage (void); | |
| 66 | void *xmalloc (char *, size_t); | |
| 984263bc MD |
67 | |
| 68 | DBTYPE type; /* Database type. */ | |
| 69 | void *infop; /* Iflags. */ | |
| 70 | u_long lineno; /* Current line in test script. */ | |
| 71 | u_int flags; /* Current DB flags. */ | |
| 72 | int ofd = STDOUT_FILENO; /* Standard output fd. */ | |
| 73 | ||
| 74 | DB *XXdbp; /* Global for gdb. */ | |
| 75 | int XXlineno; /* Fast breakpoint for gdb. */ | |
| 76 | ||
| 77 | int | |
| c9fbf0d3 | 78 | main(int argc, char *argv[]) |
| 984263bc MD |
79 | { |
| 80 | extern int optind; | |
| 81 | extern char *optarg; | |
| 82 | enum S command, state; | |
| 83 | DB *dbp; | |
| 84 | DBT data, key, keydata; | |
| 85 | size_t len; | |
| 86 | int ch, oflags, sflag; | |
| 87 | char *fname, *infoarg, *p, *t, buf[8 * 1024]; | |
| 88 | ||
| 89 | infoarg = NULL; | |
| 90 | fname = NULL; | |
| 91 | oflags = O_CREAT | O_RDWR; | |
| 92 | sflag = 0; | |
| 9b0ec895 | 93 | while ((ch = getopt(argc, argv, "f:i:lo:s")) != -1) |
| 984263bc MD |
94 | switch (ch) { |
| 95 | case 'f': | |
| 96 | fname = optarg; | |
| 97 | break; | |
| 98 | case 'i': | |
| 99 | infoarg = optarg; | |
| 100 | break; | |
| 101 | case 'l': | |
| 102 | oflags |= DB_LOCK; | |
| 103 | break; | |
| 104 | case 'o': | |
| 105 | if ((ofd = open(optarg, | |
| 106 | O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) | |
| 107 | err("%s: %s", optarg, strerror(errno)); | |
| 108 | break; | |
| 109 | case 's': | |
| 110 | sflag = 1; | |
| 111 | break; | |
| 112 | case '?': | |
| 113 | default: | |
| 114 | usage(); | |
| 115 | } | |
| 116 | argc -= optind; | |
| 117 | argv += optind; | |
| 118 | ||
| 119 | if (argc != 2) | |
| 120 | usage(); | |
| 121 | ||
| 122 | /* Set the type. */ | |
| 123 | type = dbtype(*argv++); | |
| 124 | ||
| 125 | /* Open the descriptor file. */ | |
| 126 | if (strcmp(*argv, "-") && freopen(*argv, "r", stdin) == NULL) | |
| 127 | err("%s: %s", *argv, strerror(errno)); | |
| 128 | ||
| 129 | /* Set up the db structure as necessary. */ | |
| 130 | if (infoarg == NULL) | |
| 131 | infop = NULL; | |
| 132 | else | |
| 133 | for (p = strtok(infoarg, ",\t "); p != NULL; | |
| 134 | p = strtok(0, ",\t ")) | |
| 135 | if (*p != '\0') | |
| 136 | infop = setinfo(type, p); | |
| 137 | ||
| 138 | /* | |
| 139 | * Open the DB. Delete any preexisting copy, you almost never | |
| 140 | * want it around, and it often screws up tests. | |
| 141 | */ | |
| 142 | if (fname == NULL) { | |
| 143 | p = getenv("TMPDIR"); | |
| 144 | if (p == NULL) | |
| 145 | p = "/var/tmp"; | |
| c9fbf0d3 | 146 | snprintf(buf, sizeof(buf), "%s/__dbtest", p); |
| 984263bc | 147 | fname = buf; |
| c9fbf0d3 | 148 | unlink(buf); |
| 984263bc | 149 | } else if (!sflag) |
| c9fbf0d3 | 150 | unlink(fname); |
| 984263bc MD |
151 | |
| 152 | if ((dbp = dbopen(fname, | |
| 153 | oflags, S_IRUSR | S_IWUSR, type, infop)) == NULL) | |
| 154 | err("dbopen: %s", strerror(errno)); | |
| 155 | XXdbp = dbp; | |
| 156 | ||
| 157 | state = COMMAND; | |
| 158 | for (lineno = 1; | |
| 159 | (p = fgets(buf, sizeof(buf), stdin)) != NULL; ++lineno) { | |
| 160 | /* Delete the newline, displaying the key/data is easier. */ | |
| 161 | if (ofd == STDOUT_FILENO && (t = strchr(p, '\n')) != NULL) | |
| 162 | *t = '\0'; | |
| 163 | if ((len = strlen(buf)) == 0 || isspace(*p) || *p == '#') | |
| 164 | continue; | |
| 165 | ||
| 166 | /* Convenient gdb break point. */ | |
| 167 | if (XXlineno == lineno) | |
| 168 | XXlineno = 1; | |
| 169 | switch (*p) { | |
| 170 | case 'c': /* compare */ | |
| 171 | if (state != COMMAND) | |
| 172 | err("line %lu: not expecting command", lineno); | |
| 173 | state = KEY; | |
| 174 | command = COMPARE; | |
| 175 | break; | |
| 176 | case 'e': /* echo */ | |
| 177 | if (state != COMMAND) | |
| 178 | err("line %lu: not expecting command", lineno); | |
| 179 | /* Don't display the newline, if CR at EOL. */ | |
| 180 | if (p[len - 2] == '\r') | |
| 181 | --len; | |
| 182 | if (write(ofd, p + 1, len - 1) != len - 1 || | |
| 183 | write(ofd, "\n", 1) != 1) | |
| 184 | err("write: %s", strerror(errno)); | |
| 185 | break; | |
| 186 | case 'g': /* get */ | |
| 187 | if (state != COMMAND) | |
| 188 | err("line %lu: not expecting command", lineno); | |
| 189 | state = KEY; | |
| 190 | command = GET; | |
| 191 | break; | |
| 192 | case 'p': /* put */ | |
| 193 | if (state != COMMAND) | |
| 194 | err("line %lu: not expecting command", lineno); | |
| 195 | state = KEY; | |
| 196 | command = PUT; | |
| 197 | break; | |
| 198 | case 'r': /* remove */ | |
| 199 | if (state != COMMAND) | |
| 200 | err("line %lu: not expecting command", lineno); | |
| 201 | if (flags == R_CURSOR) { | |
| 202 | rem(dbp, &key); | |
| 203 | state = COMMAND; | |
| 204 | } else { | |
| 205 | state = KEY; | |
| 206 | command = REMOVE; | |
| 207 | } | |
| 208 | break; | |
| 209 | case 'S': /* sync */ | |
| 210 | if (state != COMMAND) | |
| 211 | err("line %lu: not expecting command", lineno); | |
| 212 | synk(dbp); | |
| 213 | state = COMMAND; | |
| 214 | break; | |
| 215 | case 's': /* seq */ | |
| 216 | if (state != COMMAND) | |
| 217 | err("line %lu: not expecting command", lineno); | |
| 218 | if (flags == R_CURSOR) { | |
| 219 | state = KEY; | |
| 220 | command = SEQ; | |
| 221 | } else | |
| 222 | seq(dbp, &key); | |
| 223 | break; | |
| 224 | case 'f': | |
| 225 | flags = setflags(p + 1); | |
| 226 | break; | |
| 227 | case 'D': /* data file */ | |
| 228 | if (state != DATA) | |
| 229 | err("line %lu: not expecting data", lineno); | |
| 230 | data.data = rfile(p + 1, &data.size); | |
| 231 | goto ldata; | |
| 232 | case 'd': /* data */ | |
| 233 | if (state != DATA) | |
| 234 | err("line %lu: not expecting data", lineno); | |
| 235 | data.data = xmalloc(p + 1, len - 1); | |
| 236 | data.size = len - 1; | |
| 237 | ldata: switch (command) { | |
| 238 | case COMPARE: | |
| 239 | compare(&keydata, &data); | |
| 240 | break; | |
| 241 | case PUT: | |
| 242 | put(dbp, &key, &data); | |
| 243 | break; | |
| 244 | default: | |
| 245 | err("line %lu: command doesn't take data", | |
| 246 | lineno); | |
| 247 | } | |
| 248 | if (type != DB_RECNO) | |
| 249 | free(key.data); | |
| 250 | free(data.data); | |
| 251 | state = COMMAND; | |
| 252 | break; | |
| 253 | case 'K': /* key file */ | |
| 254 | if (state != KEY) | |
| 255 | err("line %lu: not expecting a key", lineno); | |
| 256 | if (type == DB_RECNO) | |
| 257 | err("line %lu: 'K' not available for recno", | |
| 258 | lineno); | |
| 259 | key.data = rfile(p + 1, &key.size); | |
| 260 | goto lkey; | |
| 261 | case 'k': /* key */ | |
| 262 | if (state != KEY) | |
| 263 | err("line %lu: not expecting a key", lineno); | |
| 264 | if (type == DB_RECNO) { | |
| 265 | static recno_t recno; | |
| 266 | recno = atoi(p + 1); | |
| 267 | key.data = &recno; | |
| 268 | key.size = sizeof(recno); | |
| 269 | } else { | |
| 270 | key.data = xmalloc(p + 1, len - 1); | |
| 271 | key.size = len - 1; | |
| 272 | } | |
| 273 | lkey: switch (command) { | |
| 274 | case COMPARE: | |
| 275 | getdata(dbp, &key, &keydata); | |
| 276 | state = DATA; | |
| 277 | break; | |
| 278 | case GET: | |
| 279 | get(dbp, &key); | |
| 280 | if (type != DB_RECNO) | |
| 281 | free(key.data); | |
| 282 | state = COMMAND; | |
| 283 | break; | |
| 284 | case PUT: | |
| 285 | state = DATA; | |
| 286 | break; | |
| 287 | case REMOVE: | |
| 288 | rem(dbp, &key); | |
| 289 | if ((type != DB_RECNO) && (flags != R_CURSOR)) | |
| 290 | free(key.data); | |
| 291 | state = COMMAND; | |
| 292 | break; | |
| 293 | case SEQ: | |
| 294 | seq(dbp, &key); | |
| 295 | if ((type != DB_RECNO) && (flags != R_CURSOR)) | |
| 296 | free(key.data); | |
| 297 | state = COMMAND; | |
| 298 | break; | |
| 299 | default: | |
| 300 | err("line %lu: command doesn't take a key", | |
| 301 | lineno); | |
| 302 | } | |
| 303 | break; | |
| 304 | case 'o': | |
| 305 | dump(dbp, p[1] == 'r'); | |
| 306 | break; | |
| 307 | default: | |
| 308 | err("line %lu: %s: unknown command character", | |
| 309 | lineno, p); | |
| 310 | } | |
| 311 | } | |
| 312 | #ifdef STATISTICS | |
| 313 | /* | |
| 314 | * -l must be used (DB_LOCK must be set) for this to be | |
| 315 | * used, otherwise a page will be locked and it will fail. | |
| 316 | */ | |
| 317 | if (type == DB_BTREE && oflags & DB_LOCK) | |
| 318 | __bt_stat(dbp); | |
| 319 | #endif | |
| 320 | if (dbp->close(dbp)) | |
| 321 | err("db->close: %s", strerror(errno)); | |
| c9fbf0d3 | 322 | close(ofd); |
| 984263bc MD |
323 | exit(0); |
| 324 | } | |
| 325 | ||
| 326 | #define NOOVERWRITE "put failed, would overwrite key\n" | |
| 327 | ||
| 328 | void | |
| c9fbf0d3 | 329 | compare(DBT *db1, DBT *db2) |
| 984263bc | 330 | { |
| 660c873b DR |
331 | size_t len; |
| 332 | u_char *p1, *p2; | |
| 984263bc MD |
333 | |
| 334 | if (db1->size != db2->size) | |
| 335 | printf("compare failed: key->data len %lu != data len %lu\n", | |
| 336 | db1->size, db2->size); | |
| 337 | ||
| 338 | len = MIN(db1->size, db2->size); | |
| 339 | for (p1 = db1->data, p2 = db2->data; len--;) | |
| 340 | if (*p1++ != *p2++) { | |
| 341 | printf("compare failed at offset %d\n", | |
| 342 | p1 - (u_char *)db1->data); | |
| 343 | break; | |
| 344 | } | |
| 345 | } | |
| 346 | ||
| 347 | void | |
| c9fbf0d3 | 348 | get(DB *dbp, DBT *kp) |
| 984263bc MD |
349 | { |
| 350 | DBT data; | |
| 351 | ||
| 352 | switch (dbp->get(dbp, kp, &data, flags)) { | |
| 353 | case 0: | |
| c9fbf0d3 | 354 | write(ofd, data.data, data.size); |
| 984263bc | 355 | if (ofd == STDOUT_FILENO) |
| c9fbf0d3 | 356 | write(ofd, "\n", 1); |
| 984263bc MD |
357 | break; |
| 358 | case -1: | |
| 359 | err("line %lu: get: %s", lineno, strerror(errno)); | |
| 360 | /* NOTREACHED */ | |
| 361 | case 1: | |
| 362 | #define NOSUCHKEY "get failed, no such key\n" | |
| 363 | if (ofd != STDOUT_FILENO) | |
| c9fbf0d3 | 364 | write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1); |
| 984263bc | 365 | else |
| c9fbf0d3 | 366 | fprintf(stderr, "%d: %.*s: %s", |
| 984263bc MD |
367 | lineno, MIN(kp->size, 20), kp->data, NOSUCHKEY); |
| 368 | #undef NOSUCHKEY | |
| 369 | break; | |
| 370 | } | |
| 371 | } | |
| 372 | ||
| 373 | void | |
| c9fbf0d3 | 374 | getdata(DB *dbp, DBT *kp, DBT *dp) |
| 984263bc MD |
375 | { |
| 376 | switch (dbp->get(dbp, kp, dp, flags)) { | |
| 377 | case 0: | |
| 378 | return; | |
| 379 | case -1: | |
| 380 | err("line %lu: getdata: %s", lineno, strerror(errno)); | |
| 381 | /* NOTREACHED */ | |
| 382 | case 1: | |
| 383 | err("line %lu: getdata failed, no such key", lineno); | |
| 384 | /* NOTREACHED */ | |
| 385 | } | |
| 386 | } | |
| 387 | ||
| 388 | void | |
| c9fbf0d3 | 389 | put(DB *dbp, DBT *kp, DBT *dp) |
| 984263bc MD |
390 | { |
| 391 | switch (dbp->put(dbp, kp, dp, flags)) { | |
| 392 | case 0: | |
| 393 | break; | |
| 394 | case -1: | |
| 395 | err("line %lu: put: %s", lineno, strerror(errno)); | |
| 396 | /* NOTREACHED */ | |
| 397 | case 1: | |
| c9fbf0d3 | 398 | write(ofd, NOOVERWRITE, sizeof(NOOVERWRITE) - 1); |
| 984263bc MD |
399 | break; |
| 400 | } | |
| 401 | } | |
| 402 | ||
| 403 | void | |
| c9fbf0d3 | 404 | rem(DB *dbp, DBT *kp) |
| 984263bc MD |
405 | { |
| 406 | switch (dbp->del(dbp, kp, flags)) { | |
| 407 | case 0: | |
| 408 | break; | |
| 409 | case -1: | |
| 410 | err("line %lu: rem: %s", lineno, strerror(errno)); | |
| 411 | /* NOTREACHED */ | |
| 412 | case 1: | |
| 413 | #define NOSUCHKEY "rem failed, no such key\n" | |
| 414 | if (ofd != STDOUT_FILENO) | |
| c9fbf0d3 | 415 | write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1); |
| 984263bc | 416 | else if (flags != R_CURSOR) |
| c9fbf0d3 | 417 | fprintf(stderr, "%d: %.*s: %s", |
| 984263bc MD |
418 | lineno, MIN(kp->size, 20), kp->data, NOSUCHKEY); |
| 419 | else | |
| c9fbf0d3 | 420 | fprintf(stderr, |
| 984263bc MD |
421 | "%d: rem of cursor failed\n", lineno); |
| 422 | #undef NOSUCHKEY | |
| 423 | break; | |
| 424 | } | |
| 425 | } | |
| 426 | ||
| 427 | void | |
| c9fbf0d3 | 428 | synk(DB *dbp) |
| 984263bc MD |
429 | { |
| 430 | switch (dbp->sync(dbp, flags)) { | |
| 431 | case 0: | |
| 432 | break; | |
| 433 | case -1: | |
| 434 | err("line %lu: synk: %s", lineno, strerror(errno)); | |
| 435 | /* NOTREACHED */ | |
| 436 | } | |
| 437 | } | |
| 438 | ||
| 439 | void | |
| c9fbf0d3 | 440 | seq(DB *dbp, DBT *kp) |
| 984263bc MD |
441 | { |
| 442 | DBT data; | |
| 443 | ||
| 444 | switch (dbp->seq(dbp, kp, &data, flags)) { | |
| 445 | case 0: | |
| c9fbf0d3 | 446 | write(ofd, data.data, data.size); |
| 984263bc | 447 | if (ofd == STDOUT_FILENO) |
| c9fbf0d3 | 448 | write(ofd, "\n", 1); |
| 984263bc MD |
449 | break; |
| 450 | case -1: | |
| 451 | err("line %lu: seq: %s", lineno, strerror(errno)); | |
| 452 | /* NOTREACHED */ | |
| 453 | case 1: | |
| 454 | #define NOSUCHKEY "seq failed, no such key\n" | |
| 455 | if (ofd != STDOUT_FILENO) | |
| c9fbf0d3 | 456 | write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1); |
| 984263bc | 457 | else if (flags == R_CURSOR) |
| c9fbf0d3 | 458 | fprintf(stderr, "%d: %.*s: %s", |
| 984263bc MD |
459 | lineno, MIN(kp->size, 20), kp->data, NOSUCHKEY); |
| 460 | else | |
| c9fbf0d3 | 461 | fprintf(stderr, |
| 984263bc MD |
462 | "%d: seq (%s) failed\n", lineno, sflags(flags)); |
| 463 | #undef NOSUCHKEY | |
| 464 | break; | |
| 465 | } | |
| 466 | } | |
| 467 | ||
| 468 | void | |
| c9fbf0d3 | 469 | dump(DB *dbp, int rev) |
| 984263bc MD |
470 | { |
| 471 | DBT key, data; | |
| 472 | int flags, nflags; | |
| 473 | ||
| 474 | if (rev) { | |
| 475 | flags = R_LAST; | |
| 476 | nflags = R_PREV; | |
| 477 | } else { | |
| 478 | flags = R_FIRST; | |
| 479 | nflags = R_NEXT; | |
| 480 | } | |
| 481 | for (;; flags = nflags) | |
| 482 | switch (dbp->seq(dbp, &key, &data, flags)) { | |
| 483 | case 0: | |
| c9fbf0d3 | 484 | write(ofd, data.data, data.size); |
| 984263bc | 485 | if (ofd == STDOUT_FILENO) |
| c9fbf0d3 | 486 | write(ofd, "\n", 1); |
| 984263bc MD |
487 | break; |
| 488 | case 1: | |
| 489 | goto done; | |
| 490 | case -1: | |
| 491 | err("line %lu: (dump) seq: %s", | |
| 492 | lineno, strerror(errno)); | |
| 493 | /* NOTREACHED */ | |
| 494 | } | |
| 495 | done: return; | |
| 496 | } | |
| 497 | ||
| 498 | u_int | |
| c9fbf0d3 | 499 | setflags(char *s) |
| 984263bc MD |
500 | { |
| 501 | char *p, *index(); | |
| 502 | ||
| 503 | for (; isspace(*s); ++s); | |
| 504 | if (*s == '\n' || *s == '\0') | |
| 505 | return (0); | |
| 506 | if ((p = index(s, '\n')) != NULL) | |
| 507 | *p = '\0'; | |
| 508 | if (!strcmp(s, "R_CURSOR")) return (R_CURSOR); | |
| 509 | if (!strcmp(s, "R_FIRST")) return (R_FIRST); | |
| 510 | if (!strcmp(s, "R_IAFTER")) return (R_IAFTER); | |
| 511 | if (!strcmp(s, "R_IBEFORE")) return (R_IBEFORE); | |
| 512 | if (!strcmp(s, "R_LAST")) return (R_LAST); | |
| 513 | if (!strcmp(s, "R_NEXT")) return (R_NEXT); | |
| 514 | if (!strcmp(s, "R_NOOVERWRITE")) return (R_NOOVERWRITE); | |
| 515 | if (!strcmp(s, "R_PREV")) return (R_PREV); | |
| 516 | if (!strcmp(s, "R_SETCURSOR")) return (R_SETCURSOR); | |
| 517 | ||
| 518 | err("line %lu: %s: unknown flag", lineno, s); | |
| 519 | /* NOTREACHED */ | |
| 520 | } | |
| 521 | ||
| 522 | char * | |
| c9fbf0d3 | 523 | sflags(int flags) |
| 984263bc MD |
524 | { |
| 525 | switch (flags) { | |
| 526 | case R_CURSOR: return ("R_CURSOR"); | |
| 527 | case R_FIRST: return ("R_FIRST"); | |
| 528 | case R_IAFTER: return ("R_IAFTER"); | |
| 529 | case R_IBEFORE: return ("R_IBEFORE"); | |
| 530 | case R_LAST: return ("R_LAST"); | |
| 531 | case R_NEXT: return ("R_NEXT"); | |
| 532 | case R_NOOVERWRITE: return ("R_NOOVERWRITE"); | |
| 533 | case R_PREV: return ("R_PREV"); | |
| 534 | case R_SETCURSOR: return ("R_SETCURSOR"); | |
| 535 | } | |
| 536 | ||
| 537 | return ("UNKNOWN!"); | |
| 538 | } | |
| 539 | ||
| 540 | DBTYPE | |
| c9fbf0d3 | 541 | dbtype(char *s) |
| 984263bc MD |
542 | { |
| 543 | if (!strcmp(s, "btree")) | |
| 544 | return (DB_BTREE); | |
| 545 | if (!strcmp(s, "hash")) | |
| 546 | return (DB_HASH); | |
| 547 | if (!strcmp(s, "recno")) | |
| 548 | return (DB_RECNO); | |
| 549 | err("%s: unknown type (use btree, hash or recno)", s); | |
| 550 | /* NOTREACHED */ | |
| 551 | } | |
| 552 | ||
| 553 | void * | |
| c9fbf0d3 | 554 | setinfo(DBTYPE type, char *s) |
| 984263bc MD |
555 | { |
| 556 | static BTREEINFO ib; | |
| 557 | static HASHINFO ih; | |
| 558 | static RECNOINFO rh; | |
| 559 | char *eq, *index(); | |
| 560 | ||
| 561 | if ((eq = index(s, '=')) == NULL) | |
| 562 | err("%s: illegal structure set statement", s); | |
| 563 | *eq++ = '\0'; | |
| 564 | if (!isdigit(*eq)) | |
| 565 | err("%s: structure set statement must be a number", s); | |
| 566 | ||
| 567 | switch (type) { | |
| 568 | case DB_BTREE: | |
| 569 | if (!strcmp("flags", s)) { | |
| 570 | ib.flags = atoi(eq); | |
| 571 | return (&ib); | |
| 572 | } | |
| 573 | if (!strcmp("cachesize", s)) { | |
| 574 | ib.cachesize = atoi(eq); | |
| 575 | return (&ib); | |
| 576 | } | |
| 577 | if (!strcmp("maxkeypage", s)) { | |
| 578 | ib.maxkeypage = atoi(eq); | |
| 579 | return (&ib); | |
| 580 | } | |
| 581 | if (!strcmp("minkeypage", s)) { | |
| 582 | ib.minkeypage = atoi(eq); | |
| 583 | return (&ib); | |
| 584 | } | |
| 585 | if (!strcmp("lorder", s)) { | |
| 586 | ib.lorder = atoi(eq); | |
| 587 | return (&ib); | |
| 588 | } | |
| 589 | if (!strcmp("psize", s)) { | |
| 590 | ib.psize = atoi(eq); | |
| 591 | return (&ib); | |
| 592 | } | |
| 593 | break; | |
| 594 | case DB_HASH: | |
| 595 | if (!strcmp("bsize", s)) { | |
| 596 | ih.bsize = atoi(eq); | |
| 597 | return (&ih); | |
| 598 | } | |
| 599 | if (!strcmp("ffactor", s)) { | |
| 600 | ih.ffactor = atoi(eq); | |
| 601 | return (&ih); | |
| 602 | } | |
| 603 | if (!strcmp("nelem", s)) { | |
| 604 | ih.nelem = atoi(eq); | |
| 605 | return (&ih); | |
| 606 | } | |
| 607 | if (!strcmp("cachesize", s)) { | |
| 608 | ih.cachesize = atoi(eq); | |
| 609 | return (&ih); | |
| 610 | } | |
| 611 | if (!strcmp("lorder", s)) { | |
| 612 | ih.lorder = atoi(eq); | |
| 613 | return (&ih); | |
| 614 | } | |
| 615 | break; | |
| 616 | case DB_RECNO: | |
| 617 | if (!strcmp("flags", s)) { | |
| 618 | rh.flags = atoi(eq); | |
| 619 | return (&rh); | |
| 620 | } | |
| 621 | if (!strcmp("cachesize", s)) { | |
| 622 | rh.cachesize = atoi(eq); | |
| 623 | return (&rh); | |
| 624 | } | |
| 625 | if (!strcmp("lorder", s)) { | |
| 626 | rh.lorder = atoi(eq); | |
| 627 | return (&rh); | |
| 628 | } | |
| 629 | if (!strcmp("reclen", s)) { | |
| 630 | rh.reclen = atoi(eq); | |
| 631 | return (&rh); | |
| 632 | } | |
| 633 | if (!strcmp("bval", s)) { | |
| 634 | rh.bval = atoi(eq); | |
| 635 | return (&rh); | |
| 636 | } | |
| 637 | if (!strcmp("psize", s)) { | |
| 638 | rh.psize = atoi(eq); | |
| 639 | return (&rh); | |
| 640 | } | |
| 641 | break; | |
| 642 | } | |
| 643 | err("%s: unknown structure value", s); | |
| 644 | /* NOTREACHED */ | |
| 645 | } | |
| 646 | ||
| 647 | void * | |
| c9fbf0d3 | 648 | rfile(char *name, size_t *lenp) |
| 984263bc MD |
649 | { |
| 650 | struct stat sb; | |
| 651 | void *p; | |
| 652 | int fd; | |
| 653 | char *np, *index(); | |
| 654 | ||
| 655 | for (; isspace(*name); ++name); | |
| 656 | if ((np = index(name, '\n')) != NULL) | |
| 657 | *np = '\0'; | |
| 658 | if ((fd = open(name, O_RDONLY, 0)) < 0 || | |
| 659 | fstat(fd, &sb)) | |
| 660 | err("%s: %s\n", name, strerror(errno)); | |
| 661 | #ifdef NOT_PORTABLE | |
| 662 | if (sb.st_size > (off_t)SIZE_T_MAX) | |
| 663 | err("%s: %s\n", name, strerror(E2BIG)); | |
| 664 | #endif | |
| 665 | if ((p = (void *)malloc((u_int)sb.st_size)) == NULL) | |
| 666 | err("%s", strerror(errno)); | |
| c9fbf0d3 | 667 | read(fd, p, (int)sb.st_size); |
| 984263bc | 668 | *lenp = sb.st_size; |
| c9fbf0d3 | 669 | close(fd); |
| 984263bc MD |
670 | return (p); |
| 671 | } | |
| 672 | ||
| 673 | void * | |
| c9fbf0d3 | 674 | xmalloc(char *text, size_t len) |
| 984263bc MD |
675 | { |
| 676 | void *p; | |
| 677 | ||
| 678 | if ((p = (void *)malloc(len)) == NULL) | |
| 679 | err("%s", strerror(errno)); | |
| 680 | memmove(p, text, len); | |
| 681 | return (p); | |
| 682 | } | |
| 683 | ||
| 684 | void | |
| c9fbf0d3 | 685 | usage(void) |
| 984263bc | 686 | { |
| c9fbf0d3 | 687 | fprintf(stderr, |
| 984263bc MD |
688 | "usage: dbtest [-l] [-f file] [-i info] [-o file] type script\n"); |
| 689 | exit(1); | |
| 690 | } | |
| 691 | ||
| 984263bc | 692 | #include <stdarg.h> |
| 984263bc MD |
693 | |
| 694 | void | |
| 984263bc | 695 | err(const char *fmt, ...) |
| 984263bc MD |
696 | { |
| 697 | va_list ap; | |
| 984263bc | 698 | va_start(ap, fmt); |
| c9fbf0d3 SW |
699 | fprintf(stderr, "dbtest: "); |
| 700 | vfprintf(stderr, fmt, ap); | |
| 984263bc | 701 | va_end(ap); |
| c9fbf0d3 | 702 | fprintf(stderr, "\n"); |
| 984263bc MD |
703 | exit(1); |
| 704 | /* NOTREACHED */ | |
| 705 | } |