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