More spring-cleaning.
[dragonfly.git] / contrib / libio / dbz / dbzmain.c
1 /*
2  * dbz - use and test dbz in various ways
3  *
4  * -Log-
5  */
6
7 #include <stdio.h>
8 #include <sys/types.h>
9 #include <sys/stat.h>
10 #include <string.h>
11 #include <dbz.h>
12
13 #ifdef FUNNYSEEKS
14 #include <unistd.h>
15 #else
16 #define SEEK_SET        0
17 #endif
18
19 #define STREQ(a, b)     (*(a) == *(b) && strcmp((a), (b)) == 0)
20
21 #ifndef lint
22 static char RCSid[] = "$Header: /egcs/carton/cvsfiles/egcs/./libio/dbz/dbzmain.c,v 1.1.1.1 1997/08/21 22:58:23 jason Exp $";
23 #endif
24
25 char *progname;
26
27 char *inname = "(no file)";             /* filename for messages etc. */
28 long lineno;                            /* line number for messages etc. */
29
30 char *my_basename;
31 char *pagname;
32 char *dir_name;
33 char *str2dup();
34 FILE *base;
35
36 int op = 'b';                   /* what to do, default build a new table */
37 int baseinput = 1;              /* is the base file also the input? */
38
39 char *from = NULL;              /* old table to use for dbzagain() */
40 int omitzero = 0;               /* omit lines tagged with 0 */
41 long every = 0;                 /* report every n lines */
42 int syncs = 0;                  /* dbzsync() on each report */
43 int quick = 0;                  /* quick checking, not too thorough */
44 int sweep = 0;                  /* sweep file checking all offsets */
45 int useincore = 1;              /* should we use incore facility? */
46 long xxx = 0;                   /* debugging variable */
47 int printx = 0;                 /* print xxx after all is done */
48 int unique = 1;                 /* before store(), check with fetch() */
49 int usefresh = 0;               /* use dbzfresh? */
50 long siz = 0;                   /* -p size */
51 char map = 'C';                 /* -p map */
52 long tag = 0;                   /* -p tag mask */
53 int exact = 0;                  /* do not run dbzsize(siz) */
54 int dbzint = 1;                 /* use new interface? */
55 char fs = '\t';                 /* field separator, default tab */
56 int unopen = 0;                 /* make base unopenable during dbminit? */
57 char *change = NULL;            /* chdir here before dbmclose */
58
59 #define DEFBUF  1024            /* default line-buffer size */
60 int buflen = DEFBUF;            /* line length limit */
61 char lbuf[DEFBUF];
62 char *line = lbuf;
63 char cbuf[DEFBUF];
64 char *cmp = cbuf;
65
66 void fail();
67 void dofile();
68 void runs();
69 void dosweep();
70 void mkfiles();
71 void crfile();
72 void doline();
73 void process();
74
75 #ifdef HAVERFCIZE
76 extern char *rfc822ize();
77 #else
78 #define rfc822ize(n)    (n)
79 #endif
80
81 extern char *malloc();
82
83 /*
84  - main - parse arguments and handle options
85  */
86 int
87 main(argc, argv)
88 int argc;
89 char *argv[];
90 {
91         int c;
92         int errflg = 0;
93         extern int optind;
94         extern char *optarg;
95         int doruns = 0;
96         extern long atol();
97
98         progname = argv[0];
99
100         while ((c = getopt(argc, argv, "axcmt:l:R0E:SqOiX:Yuf:p:eMUC:d")) != EOF)
101                 switch (c) {
102                 case 'a':       /* append to existing table */
103                         if (op != 'b')
104                                 fail("only one of -a -x -c -m can be given", "");
105                         op = 'a';
106                         baseinput = 0;
107                         break;
108                 case 'x':       /* extract from existing table */
109                         if (op != 'b')
110                                 fail("only one of -a -x -c -m can be given", "");
111                         op = 'x';
112                         baseinput = 0;
113                         break;
114                 case 'c':       /* check existing table */
115                         if (op != 'b')
116                                 fail("only one of -a -x -c -m can be given", "");
117                         op = 'c';
118                         break;
119                 case 'm':       /* extract missing (complement of -x) */
120                         if (op != 'b')
121                                 fail("only one of -a -x -c -m can be given", "");
122                         op = 'm';
123                         baseinput = 0;
124                         break;
125                 case 't':       /* set field separator */
126                         if (strlen(optarg) > 1)
127                                 fail("only one field separator allowed", "");
128                         fs = *optarg;
129                         break;
130                 case 'l':       /* override line-length limit */
131                         buflen = atoi(optarg) + 1;
132                         if (buflen <= 2)
133                                 fail("bad -l value `%s'", optarg);
134                         line = malloc(buflen);
135                         cmp = malloc(buflen);
136                         if (line == NULL || cmp == NULL)
137                                 fail("cannot allocate %s-byte buffers", optarg);
138                         break;
139                 case 'R':       /* print run statistics */
140                         doruns = 1;
141                         break;
142                 case '0':       /* omit lines tagged (by fake -t) with 0 */
143                         omitzero = 1;
144                         break;
145                 case 'E':       /* report every n items */
146                         every = atol(optarg);
147                         break;
148                 case 'S':       /* dbzsync() on each -E report */
149                         syncs = 1;
150                         break;
151                 case 'q':       /* quick check or extract */
152                         quick = 1;
153                         break;
154                 case 'O':       /* sweep file checking all offsets */
155                         sweep = 1;
156                         break;
157                 case 'i':       /* don't use incore */
158                         useincore = 0;
159                         break;
160                 case 'X':       /* set xxx */
161                         xxx = atoi(optarg);
162                         break;
163                 case 'Y':       /* print xxx afterward */
164                         printx = 1;
165                         break;
166                 case 'u':       /* don't check uniqueness */
167                         unique = 0;
168                         break;
169                 case 'f':       /* init from existing table's parameters */
170                         from = optarg;
171                         break;
172                 case 'p':       /* parameters for dbzfresh */
173                         if (sscanf(optarg, "%ld %1s %lx", &siz, &map, &tag) != 3) {
174                                 map = '?';
175                                 tag = 0;
176                                 if (sscanf(optarg, "%ld", &siz) != 1)
177                                         fail("bad -n value `%s'", optarg);
178                         }
179                         usefresh = 1;
180                         break;
181                 case 'e':       /* -p size is exact, don't dbzsize() it */
182                         exact = 1;
183                         break;
184                 case 'M':       /* use old dbm interface + rfc822ize */
185                         dbzint = 0;
186                         break;
187                 case 'U':       /* make base unopenable during init */
188                         unopen = 1;
189                         break;
190                 case 'C':       /* change directories before dbmclose */
191                         change = optarg;
192                         break;
193                 case 'd':       /* Debugging. */
194                         if (dbzdebug(1) < 0)
195                                 fail("dbz debugging not available", "");
196                         break;
197                 case '?':
198                 default:
199                         errflg++;
200                         break;
201                 }
202         if (errflg || optind >= argc || (optind+1 < argc && baseinput)) {
203                 fprintf(stderr, "usage: %s ", progname);
204                 fprintf(stderr, "[-a] [-x] [-c] database [file] ...\n");
205                 exit(2);
206         }
207
208         (void) dbzincore(useincore);
209         my_basename = argv[optind];
210         pagname = str2dup(my_basename, ".pag");
211         dir_name = str2dup(my_basename, ".dir");
212         mkfiles();
213         optind++;
214
215         if (baseinput)          /* implies no further arguments */
216                 process(base, my_basename);
217         else if (optind >= argc)
218                 process(stdin, "stdin");
219         else
220                 for (; optind < argc; optind++)
221                         dofile(argv[optind]);
222
223         if (change != NULL)
224                 (void) chdir(change);
225         if (dbmclose() < 0)
226                 fail("dbmclose failed", "");
227         if (doruns)
228                 runs(pagname);
229         if (sweep)
230                 dosweep(my_basename, pagname);
231         if (printx)
232                 printf("%ld\n", xxx);
233 #ifdef DBZ_FINISH
234         DBZ_FINISH;
235 #endif
236         exit(0);
237 }
238
239 /*
240  - dofile - open a file and invoke process()
241  */
242 void
243 dofile(name)
244 char *name;
245 {
246         register FILE *in;
247
248         if (STREQ(name, "-"))
249                 process(stdin, "-");
250         else {
251                 in = fopen(name, "r");
252                 if (in == NULL)
253                         fail("cannot open `%s'", name);
254                 process(in, name);
255                 (void) fclose(in);
256         }
257 }
258
259 /*
260  - mkfiles - create empty files and open them up
261  */
262 void
263 mkfiles()
264 {
265         if (op == 'b' && !dbzint) {
266                 crfile(dir_name);
267                 crfile(pagname);
268         }
269
270         base = fopen(my_basename, (op == 'a') ? "a" : "r");
271         if (base == NULL)
272                 fail("cannot open `%s'", my_basename);
273         if (unopen)
274                 (void) chmod(my_basename, 0);
275         if (from != NULL) {
276                 if (dbzagain(my_basename, from) < 0)
277                         fail("dbzagain(`%s'...) failed", my_basename);
278         } else if (op == 'b' && dbzint) {
279                 if (!exact)
280                         siz = dbzsize(siz);
281                 if (dbzfresh(my_basename, siz, (int)fs, map, (off_t)tag) < 0)
282                         fail("dbzfresh(`%s'...) failed", my_basename);
283         } else if (dbminit(my_basename) < 0)
284                 fail("dbminit(`%s') failed", my_basename);
285         if (unopen)
286                 (void) chmod(my_basename, 0600);        /* hard to restore original */
287 }
288
289 /*
290  - crfile - create a file
291  */
292 void
293 crfile(name)
294 char *name;
295 {
296         register int f;
297
298         f = creat(name, 0666);
299         if (f < 0)
300                 fail("cannot create `%s'", name);
301         (void) close(f);
302 }
303
304 /*
305  - process - process input file
306  */
307 void
308 process(in, name)
309 FILE *in;
310 char *name;
311 {
312         register off_t place;
313
314         inname = name;
315         lineno = 0;
316
317         for (;;) {
318                 place = ftell(in);
319                 if (fgets(line, buflen, in) == NULL)
320                         return;
321                 lineno++;
322                 if (every > 0 && lineno%every == 0) {
323                         fprintf(stderr, "%ld\n", lineno);
324                         if (dbzsync() < 0)
325                                 fail("dbzsync failed", "");
326                 }
327                 doline(line, place);
328         }
329         /* NOTREACHED */
330 }
331
332 /*
333  - doline - process input line
334  */
335 void
336 doline(lp, inoffset)
337 char *lp;
338 off_t inoffset;
339 {
340         register char *p;
341         register char pc;
342         datum key, value;
343         off_t place = inoffset;
344         register int shouldfind;
345         register int llen;
346         char keytext[DBZMAXKEY+1];
347
348         p = NULL;
349         if (fs != '\0')
350                 p = strchr(lp, fs);
351         if (p == NULL)
352                 p = lp + strlen(lp);
353         if (p > lp && *(p-1) == '\n')
354                 p--;
355         if (p - lp > DBZMAXKEY)
356                 fail("key of `%.40s...' too long", lp);
357         pc = *p;
358         *p = '\0';
359         (void) strcpy(keytext, lp);
360         *p = pc;
361         key.dptr = (dbzint) ? keytext : rfc822ize(keytext);
362         key.dsize = strlen(keytext)+1;
363
364         switch (op) {
365         case 'a':
366                 place = ftell(base);
367                 llen = strlen(lp);
368                 if (fwrite(lp, 1, llen, base) != llen)
369                         fail("write error in `%s'", my_basename);
370                 /* FALLTHROUGH */
371         case 'b':
372                 if (omitzero && p != NULL && *(p+1) == '0')
373                         return;
374                 if (unique) {
375                         value = (dbzint) ? dbzfetch(key) : fetch(key);
376                         if (value.dptr != NULL)
377                                 fail("`%.40s...' already present", lp);
378                 }
379                 value.dptr = (char *)&place;
380                 value.dsize = (int)sizeof(off_t);
381                 if (((dbzint) ? dbzstore(key, value) : store(key, value)) < 0)
382                         fail("store failed on `%.40s...'", lp);
383                 break;
384         case 'c':
385                 value = (dbzint) ? dbzfetch(key) : fetch(key);
386                 shouldfind = (omitzero && p != NULL && *(p+1) == '0') ? 0 : 1;
387                 if (!shouldfind && (value.dptr != NULL || value.dsize != 0))
388                         fail("`%.40s...' found, shouldn't be", lp);
389                 if (shouldfind && (value.dptr == NULL ||
390                                         value.dsize != sizeof(off_t)))
391                         fail("can't find `%.40s...'", lp);
392                 if (shouldfind && !quick) {
393                         (void) memcpy((char *)&place, value.dptr, sizeof(off_t));
394                         if (place != inoffset)
395                                 fail("offset mismatch on `%.40s...'", lp);
396                         if (fseek(base, place, SEEK_SET) == -1)
397                                 fail("fseek failed on `%.40s...'", lp);
398                         if (fgets(cmp, buflen, base) == NULL)
399                                 fail("can't read line for `%.40s...'", lp);
400                         if (!STREQ(lp, cmp))
401                                 fail("compare failed on `%.40s...'", lp);
402                 }
403                 break;
404         case 'x':
405                 value = (dbzint) ? dbzfetch(key) : fetch(key);
406                 if (value.dptr != NULL && !quick) {
407                         (void) memcpy((char *)&place, value.dptr, sizeof(off_t));
408                         if (fseek(base, place, SEEK_SET) == -1)
409                                 fail("fseek failed on `%.40s...'", lp);
410                         if (fgets(cmp, buflen, base) == NULL)
411                                 fail("can't read line for `%.40s...'", lp);
412                         fputs(cmp, stdout);
413                 } else if (value.dptr != NULL)
414                         fputs(lp, stdout);
415                 break;
416         case 'm':
417                 value = (dbzint) ? dbzfetch(key) : fetch(key);
418                 if (value.dptr == NULL) {
419                         fputs(keytext, stdout);
420                         putchar('\n');
421                 }
422                 break;
423         default:
424                 fail("unknown operator -- can't happen", "");
425                 break;
426         }
427 }
428
429 /*
430  - runs - print run statistics
431  */
432 void
433 runs(file)
434 char *file;
435 {
436         register FILE *fd;
437         off_t it;
438         register long run;
439
440         fd = fopen(file, "r");
441         if (fd == NULL)
442                 fail("cannot reopen `%s'", file);
443         run = 0;
444         while (fread((char *)&it, sizeof(off_t), 1, fd) == 1) {
445                 if (it != 0)
446                         run++;
447                 else if (run > 0) {
448                         printf("%ld\n", run);
449                         run = 0;
450                 }
451         }
452         (void) fclose(fd);
453 }
454
455 /*
456  - dosweep - sweep pag file checking for valid offsets
457  */
458 void
459 dosweep(fn, pn)
460 char *fn;
461 char *pn;
462 {
463         register FILE *pf;
464         off_t it;
465         char nl;
466         register FILE *hf;
467
468         hf = fopen(fn, "r");
469         if (hf == NULL)
470                 fail("cannot reopen `%s'", fn);
471         pf = fopen(pn, "r");
472         if (pf == NULL)
473                 fail("cannot reopen `%s'", pn);
474         while (fread((char *)&it, sizeof(off_t), 1, pf) == 1) {
475                 it = (it & ((off_t)0x80000000)) ? (it&~((off_t)0xff000000)) : it;
476                 if (it != 0 && it != 1) {       /* 0 empty, 1 known okay */
477                         it--;           /* get rid of bias */
478                         (void) fseek(hf, it-1, SEEK_SET);
479                         nl = getc(hf);
480                         if (nl != '\n')
481                                 fprintf(stderr, "offset 0%lo does not point to line\n",
482                                                                 (long)it);
483                 }
484         }
485         (void) fclose(hf);
486         (void) fclose(pf);
487 }
488
489 /*
490  - fail - complain and die
491  */
492 void
493 fail(s1, s2)
494 char *s1;
495 char *s2;
496 {
497         fprintf(stderr, "%s: (file `%s', line %ld) ", progname, inname, lineno);
498         fprintf(stderr, s1, s2);
499         fprintf(stderr, "\n");
500         exit(1);
501 }
502
503 /*
504  - str2dup - concatenate strings and malloc result
505  */
506 char *
507 str2dup(s1, s2)
508 char *s1;
509 char *s2;
510 {
511         register char *p;
512
513         p = malloc((size_t)strlen(s1) + strlen(s2) + 1);
514         if (p == NULL)
515                 fail("can't allocate space for strings", "");
516         (void) strcpy(p, s1);
517         (void) strcat(p, s2);
518         return(p);
519 }