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