1272343Sngie/* $NetBSD: h_db.c,v 1.1 2011/01/07 15:05:58 pgoyette Exp $ */ 2272343Sngie 3272343Sngie/*- 4272343Sngie * Copyright (c) 1992, 1993, 1994 5272343Sngie * The Regents of the University of California. All rights reserved. 6272343Sngie * 7272343Sngie * Redistribution and use in source and binary forms, with or without 8272343Sngie * modification, are permitted provided that the following conditions 9272343Sngie * are met: 10272343Sngie * 1. Redistributions of source code must retain the above copyright 11272343Sngie * notice, this list of conditions and the following disclaimer. 12272343Sngie * 2. Redistributions in binary form must reproduce the above copyright 13272343Sngie * notice, this list of conditions and the following disclaimer in the 14272343Sngie * documentation and/or other materials provided with the distribution. 15272343Sngie * 3. Neither the name of the University nor the names of its contributors 16272343Sngie * may be used to endorse or promote products derived from this software 17272343Sngie * without specific prior written permission. 18272343Sngie * 19272343Sngie * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20272343Sngie * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21272343Sngie * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22272343Sngie * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23272343Sngie * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24272343Sngie * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25272343Sngie * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26272343Sngie * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27272343Sngie * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28272343Sngie * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29272343Sngie * SUCH DAMAGE. 30272343Sngie */ 31272343Sngie 32272343Sngie#include <sys/cdefs.h> 33272343Sngie#ifndef lint 34272343Sngie__COPYRIGHT("@(#) Copyright (c) 1992, 1993, 1994\ 35272343Sngie The Regents of the University of California. All rights reserved."); 36272343Sngie#endif /* not lint */ 37272343Sngie 38272343Sngie#ifndef lint 39272343Sngie#if 0 40272343Sngiestatic char sccsid[] = "@(#)dbtest.c 8.17 (Berkeley) 9/1/94"; 41272343Sngie#else 42272343Sngie__RCSID("$NetBSD: h_db.c,v 1.1 2011/01/07 15:05:58 pgoyette Exp $"); 43272343Sngie#endif 44272343Sngie#endif /* not lint */ 45272343Sngie 46272343Sngie#include <sys/param.h> 47272343Sngie#include <sys/stat.h> 48272343Sngie 49272343Sngie#include <ctype.h> 50272343Sngie#include <errno.h> 51272343Sngie#include <fcntl.h> 52272343Sngie#include <limits.h> 53272343Sngie#include <stdio.h> 54272343Sngie#include <stdlib.h> 55272343Sngie#include <string.h> 56272343Sngie#include <stdbool.h> 57272343Sngie#include <unistd.h> 58272343Sngie#include <err.h> 59272343Sngie#include <db.h> 60272343Sngie 61272343Sngieenum S { COMMAND, COMPARE, GET, PUT, REMOVE, SEQ, SEQFLAG, KEY, DATA }; 62272343Sngie 63272343Sngiestatic void compare(DBT *, DBT *); 64272343Sngiestatic DBTYPE dbtype(const char *); 65272343Sngiestatic void dump(DB *, int); 66272343Sngiestatic void get(DB *, DBT *); 67272343Sngiestatic void getdata(DB *, DBT *, DBT *); 68272343Sngiestatic void put(DB *, DBT *, DBT *); 69272343Sngiestatic void rem(DB *, DBT *); 70272343Sngiestatic const char *sflags(int); 71272343Sngiestatic void synk(DB *); 72272343Sngiestatic void *rfile(char *, size_t *); 73272343Sngiestatic void seq(DB *, DBT *); 74272343Sngiestatic u_int setflags(char *); 75272343Sngiestatic void *setinfo(DBTYPE, char *); 76272343Sngiestatic void usage(void) __attribute__((__noreturn__)); 77272343Sngiestatic void *xcopy(void *, size_t); 78272343Sngiestatic void chkcmd(enum S); 79272343Sngiestatic void chkdata(enum S); 80272343Sngiestatic void chkkey(enum S); 81272343Sngie 82272343Sngie#ifdef STATISTICS 83272343Sngieextern void __bt_stat(DB *); 84272343Sngie#endif 85272343Sngie 86272343Sngiestatic DBTYPE type; /* Database type. */ 87272343Sngiestatic void *infop; /* Iflags. */ 88272343Sngiestatic size_t lineno; /* Current line in test script. */ 89272343Sngiestatic u_int flags; /* Current DB flags. */ 90272343Sngiestatic int ofd = STDOUT_FILENO; /* Standard output fd. */ 91272343Sngie 92272343Sngiestatic DB *XXdbp; /* Global for gdb. */ 93272343Sngiestatic size_t XXlineno; /* Fast breakpoint for gdb. */ 94272343Sngie 95272343Sngieint 96272343Sngiemain(int argc, char *argv[]) 97272343Sngie{ 98272343Sngie extern int optind; 99272343Sngie extern char *optarg; 100272343Sngie enum S command = COMMAND, state; 101272343Sngie DB *dbp; 102272343Sngie DBT data, key, keydata; 103272343Sngie size_t len; 104272343Sngie int ch, oflags, sflag; 105272343Sngie char *fname, *infoarg, *p, *t, buf[8 * 1024]; 106272343Sngie bool unlink_dbfile; 107272343Sngie 108272343Sngie infoarg = NULL; 109272343Sngie fname = NULL; 110272343Sngie unlink_dbfile = false; 111272343Sngie oflags = O_CREAT | O_RDWR; 112272343Sngie sflag = 0; 113272343Sngie while ((ch = getopt(argc, argv, "f:i:lo:s")) != -1) 114272343Sngie switch (ch) { 115272343Sngie case 'f': 116272343Sngie fname = optarg; 117272343Sngie break; 118272343Sngie case 'i': 119272343Sngie infoarg = optarg; 120272343Sngie break; 121272343Sngie case 'l': 122272343Sngie oflags |= DB_LOCK; 123272343Sngie break; 124272343Sngie case 'o': 125272343Sngie if ((ofd = open(optarg, 126272343Sngie O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) 127272343Sngie err(1, "Cannot create `%s'", optarg); 128272343Sngie break; 129272343Sngie case 's': 130272343Sngie sflag = 1; 131272343Sngie break; 132272343Sngie case '?': 133272343Sngie default: 134272343Sngie usage(); 135272343Sngie } 136272343Sngie argc -= optind; 137272343Sngie argv += optind; 138272343Sngie 139272343Sngie if (argc != 2) 140272343Sngie usage(); 141272343Sngie 142272343Sngie /* Set the type. */ 143272343Sngie type = dbtype(*argv++); 144272343Sngie 145272343Sngie /* Open the descriptor file. */ 146272343Sngie if (strcmp(*argv, "-") && freopen(*argv, "r", stdin) == NULL) 147272343Sngie err(1, "Cannot reopen `%s'", *argv); 148272343Sngie 149272343Sngie /* Set up the db structure as necessary. */ 150272343Sngie if (infoarg == NULL) 151272343Sngie infop = NULL; 152272343Sngie else 153272343Sngie for (p = strtok(infoarg, ",\t "); p != NULL; 154272343Sngie p = strtok(0, ",\t ")) 155272343Sngie if (*p != '\0') 156272343Sngie infop = setinfo(type, p); 157272343Sngie 158272343Sngie /* 159272343Sngie * Open the DB. Delete any preexisting copy, you almost never 160272343Sngie * want it around, and it often screws up tests. 161272343Sngie */ 162272343Sngie if (fname == NULL) { 163272343Sngie const char *q = getenv("TMPDIR"); 164272343Sngie if (q == NULL) 165272343Sngie q = "/var/tmp"; 166272343Sngie (void)snprintf(buf, sizeof(buf), "%s/__dbtest", q); 167272343Sngie fname = buf; 168272343Sngie (void)unlink(buf); 169272343Sngie unlink_dbfile = true; 170272343Sngie } else if (!sflag) 171272343Sngie (void)unlink(fname); 172272343Sngie 173272343Sngie if ((dbp = dbopen(fname, 174272343Sngie oflags, S_IRUSR | S_IWUSR, type, infop)) == NULL) 175272343Sngie err(1, "Cannot dbopen `%s'", fname); 176272343Sngie XXdbp = dbp; 177272343Sngie if (unlink_dbfile) 178272343Sngie (void)unlink(fname); 179272343Sngie 180272343Sngie state = COMMAND; 181272343Sngie for (lineno = 1; 182272343Sngie (p = fgets(buf, sizeof(buf), stdin)) != NULL; ++lineno) { 183272343Sngie /* Delete the newline, displaying the key/data is easier. */ 184272343Sngie if (ofd == STDOUT_FILENO && (t = strchr(p, '\n')) != NULL) 185272343Sngie *t = '\0'; 186272343Sngie if ((len = strlen(buf)) == 0 || isspace((unsigned char)*p) || 187272343Sngie *p == '#') 188272343Sngie continue; 189272343Sngie 190272343Sngie /* Convenient gdb break point. */ 191272343Sngie if (XXlineno == lineno) 192272343Sngie XXlineno = 1; 193272343Sngie switch (*p) { 194272343Sngie case 'c': /* compare */ 195272343Sngie chkcmd(state); 196272343Sngie state = KEY; 197272343Sngie command = COMPARE; 198272343Sngie break; 199272343Sngie case 'e': /* echo */ 200272343Sngie chkcmd(state); 201272343Sngie /* Don't display the newline, if CR at EOL. */ 202272343Sngie if (p[len - 2] == '\r') 203272343Sngie --len; 204272343Sngie if (write(ofd, p + 1, len - 1) != (ssize_t)len - 1 || 205272343Sngie write(ofd, "\n", 1) != 1) 206272343Sngie err(1, "write failed"); 207272343Sngie break; 208272343Sngie case 'g': /* get */ 209272343Sngie chkcmd(state); 210272343Sngie state = KEY; 211272343Sngie command = GET; 212272343Sngie break; 213272343Sngie case 'p': /* put */ 214272343Sngie chkcmd(state); 215272343Sngie state = KEY; 216272343Sngie command = PUT; 217272343Sngie break; 218272343Sngie case 'r': /* remove */ 219272343Sngie chkcmd(state); 220272343Sngie if (flags == R_CURSOR) { 221272343Sngie rem(dbp, &key); 222272343Sngie state = COMMAND; 223272343Sngie } else { 224272343Sngie state = KEY; 225272343Sngie command = REMOVE; 226272343Sngie } 227272343Sngie break; 228272343Sngie case 'S': /* sync */ 229272343Sngie chkcmd(state); 230272343Sngie synk(dbp); 231272343Sngie state = COMMAND; 232272343Sngie break; 233272343Sngie case 's': /* seq */ 234272343Sngie chkcmd(state); 235272343Sngie if (flags == R_CURSOR) { 236272343Sngie state = KEY; 237272343Sngie command = SEQ; 238272343Sngie } else 239272343Sngie seq(dbp, &key); 240272343Sngie break; 241272343Sngie case 'f': 242272343Sngie flags = setflags(p + 1); 243272343Sngie break; 244272343Sngie case 'D': /* data file */ 245272343Sngie chkdata(state); 246272343Sngie data.data = rfile(p + 1, &data.size); 247272343Sngie goto ldata; 248272343Sngie case 'd': /* data */ 249272343Sngie chkdata(state); 250272343Sngie data.data = xcopy(p + 1, len - 1); 251272343Sngie data.size = len - 1; 252272343Sngieldata: switch (command) { 253272343Sngie case COMPARE: 254272343Sngie compare(&keydata, &data); 255272343Sngie break; 256272343Sngie case PUT: 257272343Sngie put(dbp, &key, &data); 258272343Sngie break; 259272343Sngie default: 260272343Sngie errx(1, "line %zu: command doesn't take data", 261272343Sngie lineno); 262272343Sngie } 263272343Sngie if (type != DB_RECNO) 264272343Sngie free(key.data); 265272343Sngie free(data.data); 266272343Sngie state = COMMAND; 267272343Sngie break; 268272343Sngie case 'K': /* key file */ 269272343Sngie chkkey(state); 270272343Sngie if (type == DB_RECNO) 271272343Sngie errx(1, "line %zu: 'K' not available for recno", 272272343Sngie lineno); 273272343Sngie key.data = rfile(p + 1, &key.size); 274272343Sngie goto lkey; 275272343Sngie case 'k': /* key */ 276272343Sngie chkkey(state); 277272343Sngie if (type == DB_RECNO) { 278272343Sngie static recno_t recno; 279272343Sngie recno = atoi(p + 1); 280272343Sngie key.data = &recno; 281272343Sngie key.size = sizeof(recno); 282272343Sngie } else { 283272343Sngie key.data = xcopy(p + 1, len - 1); 284272343Sngie key.size = len - 1; 285272343Sngie } 286272343Sngielkey: switch (command) { 287272343Sngie case COMPARE: 288272343Sngie getdata(dbp, &key, &keydata); 289272343Sngie state = DATA; 290272343Sngie break; 291272343Sngie case GET: 292272343Sngie get(dbp, &key); 293272343Sngie if (type != DB_RECNO) 294272343Sngie free(key.data); 295272343Sngie state = COMMAND; 296272343Sngie break; 297272343Sngie case PUT: 298272343Sngie state = DATA; 299272343Sngie break; 300272343Sngie case REMOVE: 301272343Sngie rem(dbp, &key); 302272343Sngie if ((type != DB_RECNO) && (flags != R_CURSOR)) 303272343Sngie free(key.data); 304272343Sngie state = COMMAND; 305272343Sngie break; 306272343Sngie case SEQ: 307272343Sngie seq(dbp, &key); 308272343Sngie if ((type != DB_RECNO) && (flags != R_CURSOR)) 309272343Sngie free(key.data); 310272343Sngie state = COMMAND; 311272343Sngie break; 312272343Sngie default: 313272343Sngie errx(1, "line %zu: command doesn't take a key", 314272343Sngie lineno); 315272343Sngie } 316272343Sngie break; 317272343Sngie case 'o': 318272343Sngie dump(dbp, p[1] == 'r'); 319272343Sngie break; 320272343Sngie default: 321272343Sngie errx(1, "line %zu: %s: unknown command character", 322272343Sngie lineno, p); 323272343Sngie } 324272343Sngie } 325272343Sngie#ifdef STATISTICS 326272343Sngie /* 327272343Sngie * -l must be used (DB_LOCK must be set) for this to be 328272343Sngie * used, otherwise a page will be locked and it will fail. 329272343Sngie */ 330272343Sngie if (type == DB_BTREE && oflags & DB_LOCK) 331272343Sngie __bt_stat(dbp); 332272343Sngie#endif 333272343Sngie if ((*dbp->close)(dbp)) 334272343Sngie err(1, "db->close failed"); 335272343Sngie (void)close(ofd); 336272343Sngie return 0; 337272343Sngie} 338272343Sngie 339272343Sngie#define NOOVERWRITE "put failed, would overwrite key\n" 340272343Sngie 341272343Sngiestatic void 342272343Sngiecompare(DBT *db1, DBT *db2) 343272343Sngie{ 344272343Sngie size_t len; 345272343Sngie u_char *p1, *p2; 346272343Sngie 347272343Sngie if (db1->size != db2->size) 348272343Sngie printf("compare failed: key->data len %zu != data len %zu\n", 349272343Sngie db1->size, db2->size); 350272343Sngie 351272343Sngie len = MIN(db1->size, db2->size); 352272343Sngie for (p1 = db1->data, p2 = db2->data; len--;) 353272343Sngie if (*p1++ != *p2++) { 354272343Sngie printf("compare failed at offset %lu\n", 355272343Sngie (unsigned long)(p1 - (u_char *)db1->data)); 356272343Sngie break; 357272343Sngie } 358272343Sngie} 359272343Sngie 360272343Sngiestatic void 361272343Sngieget(DB *dbp, DBT *kp) 362272343Sngie{ 363272343Sngie DBT data; 364272343Sngie 365272343Sngie switch ((*dbp->get)(dbp, kp, &data, flags)) { 366272343Sngie case 0: 367272343Sngie (void)write(ofd, data.data, data.size); 368272343Sngie if (ofd == STDOUT_FILENO) 369272343Sngie (void)write(ofd, "\n", 1); 370272343Sngie break; 371272343Sngie case -1: 372272343Sngie err(1, "line %zu: get failed", lineno); 373272343Sngie /* NOTREACHED */ 374272343Sngie case 1: 375272343Sngie#define NOSUCHKEY "get failed, no such key\n" 376272343Sngie if (ofd != STDOUT_FILENO) 377272343Sngie (void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1); 378272343Sngie else 379272343Sngie (void)fprintf(stderr, "%zu: %.*s: %s", 380272343Sngie lineno, (int)MIN(kp->size, 20), 381272343Sngie (const char *)kp->data, 382272343Sngie NOSUCHKEY); 383272343Sngie#undef NOSUCHKEY 384272343Sngie break; 385272343Sngie } 386272343Sngie} 387272343Sngie 388272343Sngiestatic void 389272343Sngiegetdata(DB *dbp, DBT *kp, DBT *dp) 390272343Sngie{ 391272343Sngie switch ((*dbp->get)(dbp, kp, dp, flags)) { 392272343Sngie case 0: 393272343Sngie return; 394272343Sngie case -1: 395272343Sngie err(1, "line %zu: getdata failed", lineno); 396272343Sngie /* NOTREACHED */ 397272343Sngie case 1: 398272343Sngie errx(1, "line %zu: getdata failed, no such key", lineno); 399272343Sngie /* NOTREACHED */ 400272343Sngie } 401272343Sngie} 402272343Sngie 403272343Sngiestatic void 404272343Sngieput(DB *dbp, DBT *kp, DBT *dp) 405272343Sngie{ 406272343Sngie switch ((*dbp->put)(dbp, kp, dp, flags)) { 407272343Sngie case 0: 408272343Sngie break; 409272343Sngie case -1: 410272343Sngie err(1, "line %zu: put failed", lineno); 411272343Sngie /* NOTREACHED */ 412272343Sngie case 1: 413272343Sngie (void)write(ofd, NOOVERWRITE, sizeof(NOOVERWRITE) - 1); 414272343Sngie break; 415272343Sngie } 416272343Sngie} 417272343Sngie 418272343Sngiestatic void 419272343Sngierem(DB *dbp, DBT *kp) 420272343Sngie{ 421272343Sngie switch ((*dbp->del)(dbp, kp, flags)) { 422272343Sngie case 0: 423272343Sngie break; 424272343Sngie case -1: 425272343Sngie err(1, "line %zu: rem failed", lineno); 426272343Sngie /* NOTREACHED */ 427272343Sngie case 1: 428272343Sngie#define NOSUCHKEY "rem failed, no such key\n" 429272343Sngie if (ofd != STDOUT_FILENO) 430272343Sngie (void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1); 431272343Sngie else if (flags != R_CURSOR) 432272343Sngie (void)fprintf(stderr, "%zu: %.*s: %s", 433272343Sngie lineno, (int)MIN(kp->size, 20), 434272343Sngie (const char *)kp->data, NOSUCHKEY); 435272343Sngie else 436272343Sngie (void)fprintf(stderr, 437272343Sngie "%zu: rem of cursor failed\n", lineno); 438272343Sngie#undef NOSUCHKEY 439272343Sngie break; 440272343Sngie } 441272343Sngie} 442272343Sngie 443272343Sngiestatic void 444272343Sngiesynk(DB *dbp) 445272343Sngie{ 446272343Sngie switch ((*dbp->sync)(dbp, flags)) { 447272343Sngie case 0: 448272343Sngie break; 449272343Sngie case -1: 450272343Sngie err(1, "line %zu: synk failed", lineno); 451272343Sngie /* NOTREACHED */ 452272343Sngie } 453272343Sngie} 454272343Sngie 455272343Sngiestatic void 456272343Sngieseq(DB *dbp, DBT *kp) 457272343Sngie{ 458272343Sngie DBT data; 459272343Sngie 460272343Sngie switch (dbp->seq(dbp, kp, &data, flags)) { 461272343Sngie case 0: 462272343Sngie (void)write(ofd, data.data, data.size); 463272343Sngie if (ofd == STDOUT_FILENO) 464272343Sngie (void)write(ofd, "\n", 1); 465272343Sngie break; 466272343Sngie case -1: 467272343Sngie err(1, "line %zu: seq failed", lineno); 468272343Sngie /* NOTREACHED */ 469272343Sngie case 1: 470272343Sngie#define NOSUCHKEY "seq failed, no such key\n" 471272343Sngie if (ofd != STDOUT_FILENO) 472272343Sngie (void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1); 473272343Sngie else if (flags == R_CURSOR) 474272343Sngie (void)fprintf(stderr, "%zu: %.*s: %s", 475272343Sngie lineno, (int)MIN(kp->size, 20), 476272343Sngie (const char *)kp->data, NOSUCHKEY); 477272343Sngie else 478272343Sngie (void)fprintf(stderr, 479272343Sngie "%zu: seq (%s) failed\n", lineno, sflags(flags)); 480272343Sngie#undef NOSUCHKEY 481272343Sngie break; 482272343Sngie } 483272343Sngie} 484272343Sngie 485272343Sngiestatic void 486272343Sngiedump(DB *dbp, int rev) 487272343Sngie{ 488272343Sngie DBT key, data; 489272343Sngie int xflags, nflags; 490272343Sngie 491272343Sngie if (rev) { 492272343Sngie xflags = R_LAST; 493272343Sngie nflags = R_PREV; 494272343Sngie } else { 495272343Sngie xflags = R_FIRST; 496272343Sngie nflags = R_NEXT; 497272343Sngie } 498272343Sngie for (;; xflags = nflags) 499272343Sngie switch (dbp->seq(dbp, &key, &data, xflags)) { 500272343Sngie case 0: 501272343Sngie (void)write(ofd, data.data, data.size); 502272343Sngie if (ofd == STDOUT_FILENO) 503272343Sngie (void)write(ofd, "\n", 1); 504272343Sngie break; 505272343Sngie case 1: 506272343Sngie goto done; 507272343Sngie case -1: 508272343Sngie err(1, "line %zu: (dump) seq failed", lineno); 509272343Sngie /* NOTREACHED */ 510272343Sngie } 511272343Sngiedone: return; 512272343Sngie} 513272343Sngie 514272343Sngiestatic u_int 515272343Sngiesetflags(char *s) 516272343Sngie{ 517272343Sngie char *p; 518272343Sngie 519272343Sngie for (; isspace((unsigned char)*s); ++s); 520272343Sngie if (*s == '\n' || *s == '\0') 521272343Sngie return 0; 522272343Sngie if ((p = strchr(s, '\n')) != NULL) 523272343Sngie *p = '\0'; 524272343Sngie if (!strcmp(s, "R_CURSOR")) return R_CURSOR; 525272343Sngie if (!strcmp(s, "R_FIRST")) return R_FIRST; 526272343Sngie if (!strcmp(s, "R_IAFTER")) return R_IAFTER; 527272343Sngie if (!strcmp(s, "R_IBEFORE")) return R_IBEFORE; 528272343Sngie if (!strcmp(s, "R_LAST")) return R_LAST; 529272343Sngie if (!strcmp(s, "R_NEXT")) return R_NEXT; 530272343Sngie if (!strcmp(s, "R_NOOVERWRITE")) return R_NOOVERWRITE; 531272343Sngie if (!strcmp(s, "R_PREV")) return R_PREV; 532272343Sngie if (!strcmp(s, "R_SETCURSOR")) return R_SETCURSOR; 533272343Sngie 534272343Sngie errx(1, "line %zu: %s: unknown flag", lineno, s); 535272343Sngie /* NOTREACHED */ 536272343Sngie} 537272343Sngie 538272343Sngiestatic const char * 539272343Sngiesflags(int xflags) 540272343Sngie{ 541272343Sngie switch (xflags) { 542272343Sngie case R_CURSOR: return "R_CURSOR"; 543272343Sngie case R_FIRST: return "R_FIRST"; 544272343Sngie case R_IAFTER: return "R_IAFTER"; 545272343Sngie case R_IBEFORE: return "R_IBEFORE"; 546272343Sngie case R_LAST: return "R_LAST"; 547272343Sngie case R_NEXT: return "R_NEXT"; 548272343Sngie case R_NOOVERWRITE: return "R_NOOVERWRITE"; 549272343Sngie case R_PREV: return "R_PREV"; 550272343Sngie case R_SETCURSOR: return "R_SETCURSOR"; 551272343Sngie } 552272343Sngie 553272343Sngie return "UNKNOWN!"; 554272343Sngie} 555272343Sngie 556272343Sngiestatic DBTYPE 557272343Sngiedbtype(const char *s) 558272343Sngie{ 559272343Sngie if (!strcmp(s, "btree")) 560272343Sngie return DB_BTREE; 561272343Sngie if (!strcmp(s, "hash")) 562272343Sngie return DB_HASH; 563272343Sngie if (!strcmp(s, "recno")) 564272343Sngie return DB_RECNO; 565272343Sngie errx(1, "%s: unknown type (use btree, hash or recno)", s); 566272343Sngie /* NOTREACHED */ 567272343Sngie} 568272343Sngie 569272343Sngiestatic void * 570272343Sngiesetinfo(DBTYPE dtype, char *s) 571272343Sngie{ 572272343Sngie static BTREEINFO ib; 573272343Sngie static HASHINFO ih; 574272343Sngie static RECNOINFO rh; 575272343Sngie char *eq; 576272343Sngie 577272343Sngie if ((eq = strchr(s, '=')) == NULL) 578272343Sngie errx(1, "%s: illegal structure set statement", s); 579272343Sngie *eq++ = '\0'; 580272343Sngie if (!isdigit((unsigned char)*eq)) 581272343Sngie errx(1, "%s: structure set statement must be a number", s); 582272343Sngie 583272343Sngie switch (dtype) { 584272343Sngie case DB_BTREE: 585272343Sngie if (!strcmp("flags", s)) { 586272343Sngie ib.flags = atoi(eq); 587272343Sngie return &ib; 588272343Sngie } 589272343Sngie if (!strcmp("cachesize", s)) { 590272343Sngie ib.cachesize = atoi(eq); 591272343Sngie return &ib; 592272343Sngie } 593272343Sngie if (!strcmp("maxkeypage", s)) { 594272343Sngie ib.maxkeypage = atoi(eq); 595272343Sngie return &ib; 596272343Sngie } 597272343Sngie if (!strcmp("minkeypage", s)) { 598272343Sngie ib.minkeypage = atoi(eq); 599272343Sngie return &ib; 600272343Sngie } 601272343Sngie if (!strcmp("lorder", s)) { 602272343Sngie ib.lorder = atoi(eq); 603272343Sngie return &ib; 604272343Sngie } 605272343Sngie if (!strcmp("psize", s)) { 606272343Sngie ib.psize = atoi(eq); 607272343Sngie return &ib; 608272343Sngie } 609272343Sngie break; 610272343Sngie case DB_HASH: 611272343Sngie if (!strcmp("bsize", s)) { 612272343Sngie ih.bsize = atoi(eq); 613272343Sngie return &ih; 614272343Sngie } 615272343Sngie if (!strcmp("ffactor", s)) { 616272343Sngie ih.ffactor = atoi(eq); 617272343Sngie return &ih; 618272343Sngie } 619272343Sngie if (!strcmp("nelem", s)) { 620272343Sngie ih.nelem = atoi(eq); 621272343Sngie return &ih; 622272343Sngie } 623272343Sngie if (!strcmp("cachesize", s)) { 624272343Sngie ih.cachesize = atoi(eq); 625272343Sngie return &ih; 626272343Sngie } 627272343Sngie if (!strcmp("lorder", s)) { 628272343Sngie ih.lorder = atoi(eq); 629272343Sngie return &ih; 630272343Sngie } 631272343Sngie break; 632272343Sngie case DB_RECNO: 633272343Sngie if (!strcmp("flags", s)) { 634272343Sngie rh.flags = atoi(eq); 635272343Sngie return &rh; 636272343Sngie } 637272343Sngie if (!strcmp("cachesize", s)) { 638272343Sngie rh.cachesize = atoi(eq); 639272343Sngie return &rh; 640272343Sngie } 641272343Sngie if (!strcmp("lorder", s)) { 642272343Sngie rh.lorder = atoi(eq); 643272343Sngie return &rh; 644272343Sngie } 645272343Sngie if (!strcmp("reclen", s)) { 646272343Sngie rh.reclen = atoi(eq); 647272343Sngie return &rh; 648272343Sngie } 649272343Sngie if (!strcmp("bval", s)) { 650272343Sngie rh.bval = atoi(eq); 651272343Sngie return &rh; 652272343Sngie } 653272343Sngie if (!strcmp("psize", s)) { 654272343Sngie rh.psize = atoi(eq); 655272343Sngie return &rh; 656272343Sngie } 657272343Sngie break; 658272343Sngie } 659272343Sngie errx(1, "%s: unknown structure value", s); 660272343Sngie /* NOTREACHED */ 661272343Sngie} 662272343Sngie 663272343Sngiestatic void * 664272343Sngierfile(char *name, size_t *lenp) 665272343Sngie{ 666272343Sngie struct stat sb; 667272343Sngie void *p; 668272343Sngie int fd; 669272343Sngie char *np; 670272343Sngie 671272343Sngie for (; isspace((unsigned char)*name); ++name) 672272343Sngie continue; 673272343Sngie if ((np = strchr(name, '\n')) != NULL) 674272343Sngie *np = '\0'; 675272343Sngie if ((fd = open(name, O_RDONLY, 0)) == -1 || fstat(fd, &sb) == -1) 676272343Sngie err(1, "Cannot open `%s'", name); 677272343Sngie#ifdef NOT_PORTABLE 678272343Sngie if (sb.st_size > (off_t)SIZE_T_MAX) { 679272343Sngie errno = E2BIG; 680272343Sngie err("Cannot process `%s'", name); 681272343Sngie } 682272343Sngie#endif 683272343Sngie if ((p = malloc((size_t)sb.st_size)) == NULL) 684272343Sngie err(1, "Cannot allocate %zu bytes", (size_t)sb.st_size); 685272343Sngie if (read(fd, p, (ssize_t)sb.st_size) != (ssize_t)sb.st_size) 686272343Sngie err(1, "read failed"); 687272343Sngie *lenp = (size_t)sb.st_size; 688272343Sngie (void)close(fd); 689272343Sngie return p; 690272343Sngie} 691272343Sngie 692272343Sngiestatic void * 693272343Sngiexcopy(void *text, size_t len) 694272343Sngie{ 695272343Sngie void *p; 696272343Sngie 697272343Sngie if ((p = malloc(len)) == NULL) 698272343Sngie err(1, "Cannot allocate %zu bytes", len); 699272343Sngie (void)memmove(p, text, len); 700272343Sngie return p; 701272343Sngie} 702272343Sngie 703272343Sngiestatic void 704272343Sngiechkcmd(enum S state) 705272343Sngie{ 706272343Sngie if (state != COMMAND) 707272343Sngie errx(1, "line %zu: not expecting command", lineno); 708272343Sngie} 709272343Sngie 710272343Sngiestatic void 711272343Sngiechkdata(enum S state) 712272343Sngie{ 713272343Sngie if (state != DATA) 714272343Sngie errx(1, "line %zu: not expecting data", lineno); 715272343Sngie} 716272343Sngie 717272343Sngiestatic void 718272343Sngiechkkey(enum S state) 719272343Sngie{ 720272343Sngie if (state != KEY) 721272343Sngie errx(1, "line %zu: not expecting a key", lineno); 722272343Sngie} 723272343Sngie 724272343Sngiestatic void 725272343Sngieusage(void) 726272343Sngie{ 727272343Sngie (void)fprintf(stderr, 728272343Sngie "Usage: %s [-l] [-f file] [-i info] [-o file] type script\n", 729272343Sngie getprogname()); 730272343Sngie exit(1); 731272343Sngie} 732