/*- * See the file LICENSE for redistribution information. * * Copyright (c) 1996, 1997 * Sleepycat Software. All rights reserved. */ #include "config.h" #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1997\n\ Sleepycat Software Inc. All rights reserved.\n"; static const char sccsid[] = "@(#)db_load.c 10.12 (Sleepycat) 8/28/97"; #endif #ifndef NO_SYSTEM_INCLUDES #include #include #include #include #include #include #include #include #endif #include "db_int.h" #include "clib_ext.h" void badnum __P((void)); void configure __P((DB_INFO *, char **)); DB_ENV *db_init __P((char *)); int dbt_rdump __P((DBT *)); int dbt_rprint __P((DBT *)); int digitize __P((int)); int main __P((int, char *[])); void rheader __P((DBTYPE *, int *, DB_INFO *)); void usage __P((void)); const char *progname = "db_load"; /* Program name. */ int main(argc, argv) int argc; char *argv[]; { extern char *optarg; extern int optind; DB *dbp; DBT key, data; DBTYPE argtype, headertype; DB_ENV *dbenv; DB_INFO dbinfo; db_recno_t recno; int ch, pflag; char **clist, **clp, *home; /* Allocate enough room for configuration arguments. */ if ((clp = clist = calloc(argc + 1, sizeof(char *))) == NULL) err(1, NULL); home = NULL; argtype = DB_UNKNOWN; while ((ch = getopt(argc, argv, "c:f:h:t:")) != EOF) switch (ch) { case 'c': *clp++ = optarg; break; case 'f': if (freopen(optarg, "r", stdin) == NULL) err(1, "%s", optarg); break; case 'h': home = optarg; break; case 't': if (strcmp(optarg, "btree") == 0) { argtype = DB_BTREE; break; } if (strcmp(optarg, "hash") == 0) { argtype = DB_HASH; break; } usage(); /* NOTREACHED */ case '?': default: usage(); } argc -= optind; argv += optind; if (argc != 1) usage(); /* Initialize the environment. */ dbenv = db_init(home); memset(&dbinfo, 0, sizeof(DB_INFO)); /* Read the header. */ rheader(&headertype, &pflag, &dbinfo); /* Apply command-line configuration changes. */ configure(&dbinfo, clist); /* Conversion to/from recno is prohibited. */ if (argtype != DB_UNKNOWN) { if (headertype == DB_RECNO) errx(1, "databases of type recno may not be converted"); headertype = argtype; } /* Open the DB file. */ if ((errno = db_open(argv[0], headertype, DB_CREATE | DB_TRUNCATE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, dbenv, &dbinfo, &dbp)) != 0) err(1, "%s", argv[0]); /* Initialize the key/data pair. */ memset(&key, 0, sizeof(DBT)); if ((key.data = (void *)malloc(key.ulen = 1024)) == NULL) { errno = ENOMEM; err(1, NULL); } memset(&data, 0, sizeof(DBT)); if ((data.data = (void *)malloc(data.ulen = 1024)) == NULL) { errno = ENOMEM; err(1, NULL); } /* Get each key/data pair and add them to the database. */ if (headertype == DB_RECNO) { key.data = &recno; key.size = sizeof(recno); for (recno = 1;; ++recno) { if (pflag) { if (dbt_rprint(&data)) break; } else if (dbt_rdump(&data)) break; if ((errno = dbp->put(dbp, NULL, &key, &data, 0)) != 0) err(1, "%s", argv[0]); } } else for (;;) { if (pflag) { if (dbt_rprint(&key)) break; if (dbt_rprint(&data)) goto fmt; } else { if (dbt_rdump(&key)) break; if (dbt_rdump(&data)) fmt: err(1, "odd number of key/data pairs"); } if ((errno = dbp->put(dbp, NULL, &key, &data, 0)) != 0) err(1, "%s", argv[0]); } if ((errno = dbp->close(dbp, 0)) != 0) err(1, "%s", argv[0]); return (0); } /* * db_init -- * Initialize the environment. */ DB_ENV * db_init(home) char *home; { DB_ENV *dbenv; if ((dbenv = (DB_ENV *)calloc(sizeof(DB_ENV), 1)) == NULL) { errno = ENOMEM; err(1, NULL); } dbenv->db_errfile = stderr; dbenv->db_errpfx = progname; if ((errno = db_appinit(home, NULL, dbenv, DB_CREATE | DB_USE_ENVIRON)) != 0) err(1, "db_appinit"); return (dbenv); } #define FLAG(name, value, keyword, flag) \ if (strcmp(name, keyword) == 0) { \ switch (*value) { \ case '1': \ dbinfop->flags |= (flag); \ break; \ case '0': \ dbinfop->flags &= ~(flag); \ break; \ default: \ badnum(); \ /* NOTREACHED */ \ } \ continue; \ } #define NUMBER(name, value, keyword, field, flag) \ if (strcmp(name, keyword) == 0) { \ get_long(value, 1, LONG_MAX, &val); \ dbinfop->field = val; \ if (flag != 0) \ dbinfop->flags |= (flag); \ continue; \ } #define STRING(name, value, keyword, field, flag) \ if (strcmp(name, keyword) == 0) { \ dbinfop->field = value[0]; \ if (flag != 0) \ dbinfop->flags |= (flag); \ continue; \ } /* * configure -- * Handle command-line configuration options. */ void configure(dbinfop, clp) DB_INFO *dbinfop; char **clp; { long val; char *name, *value; for (; (name = *clp) != NULL; ++clp) { if ((value = strchr(name, '=')) == NULL) errx(1, "command-line configuration uses name=value format"); *value++ = '\0'; NUMBER(name, value, "bt_maxkey", bt_maxkey, 0); NUMBER(name, value, "bt_minkey", bt_minkey, 0); NUMBER(name, value, "db_lorder", db_lorder, 0); NUMBER(name, value, "db_pagesize", db_pagesize, 0); FLAG(name, value, "duplicates", DB_DUP); NUMBER(name, value, "h_ffactor", h_ffactor, 0); NUMBER(name, value, "h_nelem", h_nelem, 0); NUMBER(name, value, "re_len", re_len, DB_FIXEDLEN); STRING(name, value, "re_pad", re_pad, DB_PAD); FLAG(name, value, "recnum", DB_RECNUM); FLAG(name, value, "renumber", DB_RENUMBER); errx(1, "unknown command-line configuration keyword"); } } /* * rheader -- * Read the header message. */ void rheader(dbtypep, pflagp, dbinfop) DBTYPE *dbtypep; int *pflagp; DB_INFO *dbinfop; { long lineno, val; char name[256], value[256]; *dbtypep = DB_UNKNOWN; *pflagp = 0; for (lineno = 1;; ++lineno) { if (fscanf(stdin, "%[^=]=%s\n", name, value) != 2) errx(1, "line %lu: unexpected format", lineno); if (strcmp(name, "HEADER") == 0) break; if (strcmp(name, "format") == 0) { if (strcmp(value, "bytevalue") == 0) { *pflagp = 0; continue; } if (strcmp(value, "print") == 0) { *pflagp = 1; continue; } errx(1, "line %d: unknown format", lineno); } if (strcmp(name, "type") == 0) { if (strcmp(value, "btree") == 0) { *dbtypep = DB_BTREE; continue; } if (strcmp(value, "hash") == 0) { *dbtypep = DB_HASH; continue; } if (strcmp(value, "recno") == 0) { *dbtypep = DB_RECNO; continue; } errx(1, "line %d: unknown type", lineno); } NUMBER(name, value, "bt_maxkey", bt_maxkey, 0); NUMBER(name, value, "bt_minkey", bt_minkey, 0); NUMBER(name, value, "db_lorder", db_lorder, 0); NUMBER(name, value, "db_pagesize", db_pagesize, 0); FLAG(name, value, "duplicates", DB_DUP); NUMBER(name, value, "h_ffactor", h_ffactor, 0); NUMBER(name, value, "h_nelem", h_nelem, 0); NUMBER(name, value, "re_len", re_len, DB_FIXEDLEN); STRING(name, value, "re_pad", re_pad, DB_PAD); FLAG(name, value, "recnum", DB_RECNUM); FLAG(name, value, "renumber", DB_RENUMBER); errx(1, "unknown input-file header configuration keyword"); } } /* * dbt_rprint -- * Read a printable line into a DBT structure. */ int dbt_rprint(dbtp) DBT *dbtp; { u_int32_t len; u_int8_t *p; int c1, c2, escape; escape = 0; for (p = dbtp->data, len = 0; (c1 = getchar()) != '\n';) { if (c1 == EOF) { if (len == 0) return (1); err(1, "unexpected end of key/data pair"); } if (escape) { if (c1 != '\\') { if ((c2 = getchar()) == EOF) err(1, "unexpected end of key/data pair"); c1 = digitize(c1) << 4 | digitize(c2); } escape = 0; } else if (c1 == '\\') { escape = 1; continue; } if (++len >= dbtp->ulen - 10) { dbtp->ulen *= 2; if ((dbtp->data = (void *)realloc(dbtp->data, dbtp->ulen)) == NULL) { errno = ENOMEM; err(1, NULL); } p = (u_int8_t *)dbtp->data + len; } *p++ = c1; } dbtp->size = len; return (0); } /* * digitize -- * Convert a character to an integer. */ int digitize(c) int c; { switch (c) { /* Don't depend on ASCII ordering. */ case '0': return (0); case '1': return (1); case '2': return (2); case '3': return (3); case '4': return (4); case '5': return (5); case '6': return (6); case '7': return (7); case '8': return (8); case '9': return (9); case 'a': return (10); case 'b': return (11); case 'c': return (12); case 'd': return (13); case 'e': return (14); case 'f': return (15); } err(1, "unexpected hexadecimal value"); /* NOTREACHED */ return (0); } /* * dbt_rdump -- * Read a byte dump line into a DBT structure. */ int dbt_rdump(dbtp) DBT *dbtp; { u_int32_t len; u_int8_t *p; int c1, c2; for (p = dbtp->data, len = 0; (c1 = getchar()) != '\n';) { if (c1 == EOF) { if (len == 0) return (1); err(1, "unexpected end of key/data pair"); } if ((c2 = getchar()) == EOF) err(1, "unexpected end of key/data pair"); if (++len >= dbtp->ulen - 10) { dbtp->ulen *= 2; if ((dbtp->data = (void *)realloc(dbtp->data, dbtp->ulen)) == NULL) { errno = ENOMEM; err(1, NULL); } p = (u_int8_t *)dbtp->data + len; } *p++ = digitize(c1) << 4 | digitize(c2); } dbtp->size = len; return (0); } /* * badnum -- * Display the bad number message. */ void badnum() { err(1, "boolean name=value pairs require a value of 0 or 1"); } /* * usage -- * Display the usage message. */ void usage() { (void)fprintf(stderr, "usage: db_load [-c name=value] [-f file] [-h home] [-t btree | hash] db_file\n"); exit(1); }