]>
Commit | Line | Data |
---|---|---|
92f1da4d UD |
1 | /*- |
2 | * See the file LICENSE for redistribution information. | |
3 | * | |
4 | * Copyright (c) 1996, 1997 | |
5 | * Sleepycat Software. All rights reserved. | |
6 | */ | |
7 | ||
8 | #include "config.h" | |
9 | ||
10 | #ifndef lint | |
11 | static const char copyright[] = | |
12 | "@(#) Copyright (c) 1997\n\ | |
13 | Sleepycat Software Inc. All rights reserved.\n"; | |
af69217f | 14 | static const char sccsid[] = "@(#)db_load.c 10.15 (Sleepycat) 12/29/97"; |
92f1da4d UD |
15 | #endif |
16 | ||
17 | #ifndef NO_SYSTEM_INCLUDES | |
18 | #include <sys/types.h> | |
19 | #include <sys/stat.h> | |
20 | ||
21 | #include <errno.h> | |
92f1da4d UD |
22 | #include <limits.h> |
23 | #include <stdio.h> | |
24 | #include <stdlib.h> | |
25 | #include <string.h> | |
26b4d766 | 26 | #include <unistd.h> |
92f1da4d UD |
27 | #endif |
28 | ||
29 | #include "db_int.h" | |
30 | #include "clib_ext.h" | |
31 | ||
32 | void badnum __P((void)); | |
33 | void configure __P((DB_INFO *, char **)); | |
34 | DB_ENV *db_init __P((char *)); | |
35 | int dbt_rdump __P((DBT *)); | |
36 | int dbt_rprint __P((DBT *)); | |
37 | int digitize __P((int)); | |
26b4d766 | 38 | int main __P((int, char *[])); |
92f1da4d UD |
39 | void rheader __P((DBTYPE *, int *, DB_INFO *)); |
40 | void usage __P((void)); | |
92f1da4d | 41 | |
26b4d766 UD |
42 | const char |
43 | *progname = "db_load"; /* Program name. */ | |
92f1da4d UD |
44 | |
45 | int | |
46 | main(argc, argv) | |
47 | int argc; | |
48 | char *argv[]; | |
49 | { | |
50 | extern char *optarg; | |
51 | extern int optind; | |
52 | DB *dbp; | |
53 | DBT key, data; | |
af69217f | 54 | DBTYPE argtype, dbtype; |
92f1da4d UD |
55 | DB_ENV *dbenv; |
56 | DB_INFO dbinfo; | |
57 | db_recno_t recno; | |
af69217f | 58 | int ch, no_header, pflag; |
92f1da4d UD |
59 | char **clist, **clp, *home; |
60 | ||
61 | /* Allocate enough room for configuration arguments. */ | |
a5a0310d | 62 | if ((clp = clist = (char **)calloc(argc + 1, sizeof(char *))) == NULL) |
92f1da4d UD |
63 | err(1, NULL); |
64 | ||
65 | home = NULL; | |
af69217f UD |
66 | no_header = 0; |
67 | argtype = dbtype = DB_UNKNOWN; | |
68 | while ((ch = getopt(argc, argv, "c:f:h:Tt:")) != EOF) | |
92f1da4d UD |
69 | switch (ch) { |
70 | case 'c': | |
71 | *clp++ = optarg; | |
72 | break; | |
73 | case 'f': | |
74 | if (freopen(optarg, "r", stdin) == NULL) | |
75 | err(1, "%s", optarg); | |
76 | break; | |
77 | case 'h': | |
78 | home = optarg; | |
79 | break; | |
af69217f UD |
80 | case 'T': |
81 | no_header = pflag = 1; | |
82 | break; | |
92f1da4d UD |
83 | case 't': |
84 | if (strcmp(optarg, "btree") == 0) { | |
85 | argtype = DB_BTREE; | |
86 | break; | |
87 | } | |
88 | if (strcmp(optarg, "hash") == 0) { | |
89 | argtype = DB_HASH; | |
90 | break; | |
91 | } | |
af69217f UD |
92 | if (strcmp(optarg, "recno") == 0) { |
93 | argtype = DB_RECNO; | |
94 | break; | |
95 | } | |
92f1da4d UD |
96 | usage(); |
97 | /* NOTREACHED */ | |
98 | case '?': | |
99 | default: | |
100 | usage(); | |
101 | } | |
102 | argc -= optind; | |
103 | argv += optind; | |
104 | ||
105 | if (argc != 1) | |
106 | usage(); | |
107 | ||
108 | /* Initialize the environment. */ | |
109 | dbenv = db_init(home); | |
110 | memset(&dbinfo, 0, sizeof(DB_INFO)); | |
111 | ||
af69217f UD |
112 | /* |
113 | * Read the header. If there isn't any header, we're expecting flat | |
114 | * text, set the pflag appropriately. | |
115 | */ | |
116 | if (no_header) | |
117 | dbtype = argtype; | |
118 | else { | |
119 | rheader(&dbtype, &pflag, &dbinfo); | |
120 | if (argtype != DB_UNKNOWN) { | |
121 | /* Conversion to/from recno is prohibited. */ | |
122 | if ((dbtype == DB_RECNO && argtype != DB_RECNO) || | |
123 | (argtype == DB_RECNO && dbtype != DB_RECNO)) | |
124 | errx(1, | |
125 | "databases of type recno may not be converted"); | |
126 | dbtype = argtype; | |
127 | } | |
128 | } | |
129 | if (dbtype == DB_UNKNOWN) | |
130 | errx(1, "no database type specified"); | |
92f1da4d UD |
131 | |
132 | /* Apply command-line configuration changes. */ | |
133 | configure(&dbinfo, clist); | |
134 | ||
92f1da4d | 135 | /* Open the DB file. */ |
af69217f | 136 | if ((errno = db_open(argv[0], dbtype, DB_CREATE | DB_TRUNCATE, |
92f1da4d UD |
137 | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, |
138 | dbenv, &dbinfo, &dbp)) != 0) | |
139 | err(1, "%s", argv[0]); | |
140 | ||
141 | /* Initialize the key/data pair. */ | |
142 | memset(&key, 0, sizeof(DBT)); | |
143 | if ((key.data = (void *)malloc(key.ulen = 1024)) == NULL) { | |
144 | errno = ENOMEM; | |
145 | err(1, NULL); | |
146 | } | |
147 | memset(&data, 0, sizeof(DBT)); | |
148 | if ((data.data = (void *)malloc(data.ulen = 1024)) == NULL) { | |
149 | errno = ENOMEM; | |
150 | err(1, NULL); | |
151 | } | |
152 | ||
153 | /* Get each key/data pair and add them to the database. */ | |
af69217f | 154 | if (dbtype == DB_RECNO) { |
92f1da4d UD |
155 | key.data = &recno; |
156 | key.size = sizeof(recno); | |
157 | for (recno = 1;; ++recno) { | |
158 | if (pflag) { | |
159 | if (dbt_rprint(&data)) | |
160 | break; | |
161 | } else | |
162 | if (dbt_rdump(&data)) | |
163 | break; | |
164 | if ((errno = dbp->put(dbp, NULL, &key, &data, 0)) != 0) | |
165 | err(1, "%s", argv[0]); | |
166 | } | |
167 | } else | |
168 | for (;;) { | |
169 | if (pflag) { | |
170 | if (dbt_rprint(&key)) | |
171 | break; | |
172 | if (dbt_rprint(&data)) | |
173 | goto fmt; | |
174 | } else { | |
175 | if (dbt_rdump(&key)) | |
176 | break; | |
177 | if (dbt_rdump(&data)) | |
178 | fmt: err(1, "odd number of key/data pairs"); | |
179 | } | |
180 | if ((errno = dbp->put(dbp, NULL, &key, &data, 0)) != 0) | |
181 | err(1, "%s", argv[0]); | |
182 | } | |
183 | ||
184 | if ((errno = dbp->close(dbp, 0)) != 0) | |
185 | err(1, "%s", argv[0]); | |
186 | return (0); | |
187 | } | |
188 | ||
189 | /* | |
190 | * db_init -- | |
191 | * Initialize the environment. | |
192 | */ | |
193 | DB_ENV * | |
194 | db_init(home) | |
195 | char *home; | |
196 | { | |
197 | DB_ENV *dbenv; | |
198 | ||
199 | if ((dbenv = (DB_ENV *)calloc(sizeof(DB_ENV), 1)) == NULL) { | |
200 | errno = ENOMEM; | |
201 | err(1, NULL); | |
202 | } | |
203 | dbenv->db_errfile = stderr; | |
204 | dbenv->db_errpfx = progname; | |
205 | ||
206 | if ((errno = | |
207 | db_appinit(home, NULL, dbenv, DB_CREATE | DB_USE_ENVIRON)) != 0) | |
208 | err(1, "db_appinit"); | |
209 | return (dbenv); | |
210 | } | |
211 | ||
212 | #define FLAG(name, value, keyword, flag) \ | |
213 | if (strcmp(name, keyword) == 0) { \ | |
214 | switch (*value) { \ | |
215 | case '1': \ | |
216 | dbinfop->flags |= (flag); \ | |
217 | break; \ | |
218 | case '0': \ | |
219 | dbinfop->flags &= ~(flag); \ | |
220 | break; \ | |
221 | default: \ | |
222 | badnum(); \ | |
223 | /* NOTREACHED */ \ | |
224 | } \ | |
225 | continue; \ | |
226 | } | |
227 | #define NUMBER(name, value, keyword, field, flag) \ | |
228 | if (strcmp(name, keyword) == 0) { \ | |
229 | get_long(value, 1, LONG_MAX, &val); \ | |
230 | dbinfop->field = val; \ | |
231 | if (flag != 0) \ | |
232 | dbinfop->flags |= (flag); \ | |
233 | continue; \ | |
234 | } | |
235 | #define STRING(name, value, keyword, field, flag) \ | |
236 | if (strcmp(name, keyword) == 0) { \ | |
237 | dbinfop->field = value[0]; \ | |
238 | if (flag != 0) \ | |
239 | dbinfop->flags |= (flag); \ | |
240 | continue; \ | |
241 | } | |
242 | ||
243 | /* | |
244 | * configure -- | |
245 | * Handle command-line configuration options. | |
246 | */ | |
247 | void | |
248 | configure(dbinfop, clp) | |
249 | DB_INFO *dbinfop; | |
250 | char **clp; | |
251 | { | |
252 | long val; | |
253 | char *name, *value; | |
254 | ||
255 | for (; (name = *clp) != NULL; ++clp) { | |
256 | if ((value = strchr(name, '=')) == NULL) | |
257 | errx(1, | |
258 | "command-line configuration uses name=value format"); | |
259 | *value++ = '\0'; | |
260 | ||
261 | NUMBER(name, value, "bt_maxkey", bt_maxkey, 0); | |
262 | NUMBER(name, value, "bt_minkey", bt_minkey, 0); | |
263 | NUMBER(name, value, "db_lorder", db_lorder, 0); | |
264 | NUMBER(name, value, "db_pagesize", db_pagesize, 0); | |
265 | FLAG(name, value, "duplicates", DB_DUP); | |
266 | NUMBER(name, value, "h_ffactor", h_ffactor, 0); | |
267 | NUMBER(name, value, "h_nelem", h_nelem, 0); | |
268 | NUMBER(name, value, "re_len", re_len, DB_FIXEDLEN); | |
269 | STRING(name, value, "re_pad", re_pad, DB_PAD); | |
270 | FLAG(name, value, "recnum", DB_RECNUM); | |
271 | FLAG(name, value, "renumber", DB_RENUMBER); | |
272 | ||
273 | errx(1, "unknown command-line configuration keyword"); | |
274 | } | |
275 | } | |
276 | ||
277 | /* | |
278 | * rheader -- | |
279 | * Read the header message. | |
280 | */ | |
281 | void | |
282 | rheader(dbtypep, pflagp, dbinfop) | |
283 | DBTYPE *dbtypep; | |
284 | int *pflagp; | |
285 | DB_INFO *dbinfop; | |
286 | { | |
287 | long lineno, val; | |
288 | char name[256], value[256]; | |
289 | ||
290 | *dbtypep = DB_UNKNOWN; | |
291 | *pflagp = 0; | |
292 | ||
293 | for (lineno = 1;; ++lineno) { | |
af69217f | 294 | /* If we don't see the expected information, it's an error. */ |
92f1da4d | 295 | if (fscanf(stdin, "%[^=]=%s\n", name, value) != 2) |
26b4d766 | 296 | errx(1, "line %lu: unexpected format", lineno); |
af69217f UD |
297 | |
298 | /* Check for the end of the header lines. */ | |
92f1da4d UD |
299 | if (strcmp(name, "HEADER") == 0) |
300 | break; | |
301 | ||
302 | if (strcmp(name, "format") == 0) { | |
303 | if (strcmp(value, "bytevalue") == 0) { | |
304 | *pflagp = 0; | |
305 | continue; | |
306 | } | |
307 | if (strcmp(value, "print") == 0) { | |
308 | *pflagp = 1; | |
309 | continue; | |
310 | } | |
311 | errx(1, "line %d: unknown format", lineno); | |
312 | } | |
313 | if (strcmp(name, "type") == 0) { | |
314 | if (strcmp(value, "btree") == 0) { | |
315 | *dbtypep = DB_BTREE; | |
316 | continue; | |
317 | } | |
318 | if (strcmp(value, "hash") == 0) { | |
319 | *dbtypep = DB_HASH; | |
320 | continue; | |
321 | } | |
322 | if (strcmp(value, "recno") == 0) { | |
323 | *dbtypep = DB_RECNO; | |
324 | continue; | |
325 | } | |
326 | errx(1, "line %d: unknown type", lineno); | |
327 | } | |
328 | NUMBER(name, value, "bt_maxkey", bt_maxkey, 0); | |
329 | NUMBER(name, value, "bt_minkey", bt_minkey, 0); | |
330 | NUMBER(name, value, "db_lorder", db_lorder, 0); | |
331 | NUMBER(name, value, "db_pagesize", db_pagesize, 0); | |
332 | FLAG(name, value, "duplicates", DB_DUP); | |
333 | NUMBER(name, value, "h_ffactor", h_ffactor, 0); | |
334 | NUMBER(name, value, "h_nelem", h_nelem, 0); | |
335 | NUMBER(name, value, "re_len", re_len, DB_FIXEDLEN); | |
336 | STRING(name, value, "re_pad", re_pad, DB_PAD); | |
337 | FLAG(name, value, "recnum", DB_RECNUM); | |
338 | FLAG(name, value, "renumber", DB_RENUMBER); | |
339 | ||
340 | errx(1, "unknown input-file header configuration keyword"); | |
341 | } | |
342 | } | |
343 | ||
344 | /* | |
345 | * dbt_rprint -- | |
346 | * Read a printable line into a DBT structure. | |
347 | */ | |
348 | int | |
349 | dbt_rprint(dbtp) | |
350 | DBT *dbtp; | |
351 | { | |
352 | u_int32_t len; | |
353 | u_int8_t *p; | |
354 | int c1, c2, escape; | |
355 | ||
356 | escape = 0; | |
357 | for (p = dbtp->data, len = 0; (c1 = getchar()) != '\n';) { | |
358 | if (c1 == EOF) { | |
359 | if (len == 0) | |
360 | return (1); | |
361 | err(1, "unexpected end of key/data pair"); | |
362 | } | |
363 | if (escape) { | |
364 | if (c1 != '\\') { | |
365 | if ((c2 = getchar()) == EOF) | |
366 | err(1, | |
367 | "unexpected end of key/data pair"); | |
368 | c1 = digitize(c1) << 4 | digitize(c2); | |
369 | } | |
370 | escape = 0; | |
371 | } else | |
372 | if (c1 == '\\') { | |
373 | escape = 1; | |
374 | continue; | |
375 | } | |
cc3fa755 | 376 | if (len >= dbtp->ulen - 10) { |
92f1da4d UD |
377 | dbtp->ulen *= 2; |
378 | if ((dbtp->data = | |
379 | (void *)realloc(dbtp->data, dbtp->ulen)) == NULL) { | |
380 | errno = ENOMEM; | |
381 | err(1, NULL); | |
382 | } | |
383 | p = (u_int8_t *)dbtp->data + len; | |
384 | } | |
cc3fa755 | 385 | ++len; |
92f1da4d UD |
386 | *p++ = c1; |
387 | } | |
388 | dbtp->size = len; | |
389 | return (0); | |
390 | } | |
391 | ||
392 | /* | |
393 | * digitize -- | |
394 | * Convert a character to an integer. | |
395 | */ | |
396 | int | |
397 | digitize(c) | |
398 | int c; | |
399 | { | |
400 | switch (c) { /* Don't depend on ASCII ordering. */ | |
401 | case '0': return (0); | |
402 | case '1': return (1); | |
403 | case '2': return (2); | |
404 | case '3': return (3); | |
405 | case '4': return (4); | |
406 | case '5': return (5); | |
407 | case '6': return (6); | |
408 | case '7': return (7); | |
409 | case '8': return (8); | |
410 | case '9': return (9); | |
411 | case 'a': return (10); | |
412 | case 'b': return (11); | |
413 | case 'c': return (12); | |
414 | case 'd': return (13); | |
415 | case 'e': return (14); | |
416 | case 'f': return (15); | |
417 | } | |
418 | ||
419 | err(1, "unexpected hexadecimal value"); | |
420 | /* NOTREACHED */ | |
421 | ||
422 | return (0); | |
423 | } | |
424 | ||
425 | /* | |
426 | * dbt_rdump -- | |
427 | * Read a byte dump line into a DBT structure. | |
428 | */ | |
429 | int | |
430 | dbt_rdump(dbtp) | |
431 | DBT *dbtp; | |
432 | { | |
433 | u_int32_t len; | |
434 | u_int8_t *p; | |
435 | int c1, c2; | |
436 | ||
437 | for (p = dbtp->data, len = 0; (c1 = getchar()) != '\n';) { | |
438 | if (c1 == EOF) { | |
439 | if (len == 0) | |
440 | return (1); | |
441 | err(1, "unexpected end of key/data pair"); | |
442 | } | |
443 | if ((c2 = getchar()) == EOF) | |
444 | err(1, "unexpected end of key/data pair"); | |
cc3fa755 | 445 | if (len >= dbtp->ulen - 10) { |
92f1da4d UD |
446 | dbtp->ulen *= 2; |
447 | if ((dbtp->data = | |
448 | (void *)realloc(dbtp->data, dbtp->ulen)) == NULL) { | |
449 | errno = ENOMEM; | |
450 | err(1, NULL); | |
451 | } | |
452 | p = (u_int8_t *)dbtp->data + len; | |
453 | } | |
cc3fa755 | 454 | ++len; |
92f1da4d UD |
455 | *p++ = digitize(c1) << 4 | digitize(c2); |
456 | } | |
457 | dbtp->size = len; | |
458 | return (0); | |
459 | } | |
460 | ||
461 | /* | |
462 | * badnum -- | |
463 | * Display the bad number message. | |
464 | */ | |
465 | void | |
466 | badnum() | |
467 | { | |
468 | err(1, "boolean name=value pairs require a value of 0 or 1"); | |
469 | } | |
470 | ||
471 | /* | |
472 | * usage -- | |
473 | * Display the usage message. | |
474 | */ | |
475 | void | |
476 | usage() | |
477 | { | |
478 | (void)fprintf(stderr, | |
af69217f | 479 | "usage: db_load [-T]\n\t[-c name=value] [-f file] [-h home] [-t btree | hash] db_file\n"); |
92f1da4d UD |
480 | exit(1); |
481 | } |