home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / lib / libc / db / test / dbtest.c next >
Encoding:
C/C++ Source or Header  |  1993-06-04  |  13.9 KB  |  657 lines

  1. /*-
  2.  * Copyright (c) 1992, 1993
  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.  
  34. #ifndef lint
  35. static char copyright[] =
  36. "@(#) Copyright (c) 1992, 1993\n\
  37.     The Regents of the University of California.  All rights reserved.\n";
  38. #endif /* not lint */
  39.  
  40. #ifndef lint
  41. static char sccsid[] = "@(#)dbtest.c    8.1 (Berkeley) 6/4/93";
  42. #endif /* not lint */
  43.  
  44. #include <sys/param.h>
  45. #include <sys/stat.h>
  46.  
  47. #include <ctype.h>
  48. #include <errno.h>
  49. #include <fcntl.h>
  50. #include <limits.h>
  51. #include <stdio.h>
  52. #include <stdlib.h>
  53. #include <string.h>
  54. #include <unistd.h>
  55.  
  56. #include <db.h>
  57.  
  58. enum S { COMMAND, COMPARE, GET, PUT, REMOVE, SEQ, SEQFLAG, KEY, DATA };
  59.  
  60. void     compare __P((DBT *, DBT *));
  61. DBTYPE     dbtype __P((char *));
  62. void     dump __P((DB *, int));
  63. void     err __P((const char *, ...));
  64. void     get __P((DB *, DBT *));
  65. void     getdata __P((DB *, DBT *, DBT *));
  66. void     put __P((DB *, DBT *, DBT *));
  67. void     rem __P((DB *, DBT *));
  68. void    *rfile __P((char *, size_t *));
  69. void     seq __P((DB *, DBT *));
  70. u_int     setflags __P((char *));
  71. void    *setinfo __P((DBTYPE, char *));
  72. void     usage __P((void));
  73. void    *xmalloc __P((char *, size_t));
  74.  
  75. DBTYPE type;
  76. void *infop;
  77. u_long lineno;
  78. u_int flags;
  79. int ofd = STDOUT_FILENO;
  80.  
  81. DB *XXdbp;                /* Global for gdb. */
  82.  
  83. int
  84. main(argc, argv)
  85.     int argc;
  86.     char *argv[];
  87. {
  88.     extern int optind;
  89.     extern char *optarg;
  90.     enum S command, state;
  91.     DB *dbp;
  92.     DBT data, key, keydata;
  93.     size_t len;
  94.     int ch;
  95.     char *fname, *infoarg, *p, buf[8 * 1024];
  96.  
  97.     infoarg = NULL;
  98.     fname = NULL;
  99.     while ((ch = getopt(argc, argv, "f:i:o:")) != EOF)
  100.         switch(ch) {
  101.         case 'f':
  102.             fname = optarg;
  103.             break;
  104.         case 'i':
  105.             infoarg = optarg;
  106.             break;
  107.         case 'o':
  108.             if ((ofd = open(optarg,
  109.                 O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
  110.                 err("%s: %s", optarg, strerror(errno));
  111.             break;
  112.         case '?':
  113.         default:
  114.             usage();
  115.         }
  116.     argc -= optind;
  117.     argv += optind;
  118.  
  119.     if (argc != 2)
  120.         usage();
  121.  
  122.     /* Set the type. */
  123.     type = dbtype(*argv++);
  124.  
  125.     /* Open the descriptor file. */
  126.     if (freopen(*argv, "r", stdin) == NULL)
  127.         err("%s: %s", *argv, strerror(errno));
  128.  
  129.     /* Set up the db structure as necessary. */
  130.     if (infoarg == NULL)
  131.         infop = NULL;
  132.     else
  133.         for (p = strtok(infoarg, ",\t "); p != NULL;
  134.             p = strtok(0, ",\t "))
  135.             if (*p != '\0')
  136.                 infop = setinfo(type, p);
  137.  
  138.     /* Open the DB. */
  139.     if (fname == NULL) {
  140.         p = getenv("TMPDIR");
  141.         if (p == NULL)
  142.             p = "/var/tmp";
  143.         (void)sprintf(buf, "%s/__dbtest", p);
  144.         fname = buf;
  145.         (void)unlink(buf);
  146.     }
  147.     if ((dbp = dbopen(fname,
  148.         O_CREAT | O_RDWR, S_IRUSR | S_IWUSR, type, infop)) == NULL)
  149.         err("dbopen: %s", strerror(errno));
  150.     XXdbp = dbp;
  151.  
  152.     state = COMMAND;
  153.     for (lineno = 1;
  154.         (p = fgets(buf, sizeof(buf), stdin)) != NULL; ++lineno) {
  155.         len = strlen(buf);
  156.         switch(*p) {
  157.         case 'c':            /* compare */
  158.             if (state != COMMAND)
  159.                 err("line %lu: not expecting command", lineno);
  160.             state = KEY;
  161.             command = COMPARE;
  162.             break;
  163.         case 'e':            /* echo */
  164.             if (state != COMMAND)
  165.                 err("line %lu: not expecting command", lineno);
  166.             /* Don't display the newline, if CR at EOL. */
  167.             if (p[len - 2] == '\r')
  168.                 --len;
  169.             if (write(ofd, p + 1, len - 1) != len - 1)
  170.                 err("write: %s", strerror(errno));
  171.             break;
  172.         case 'g':            /* get */
  173.             if (state != COMMAND)
  174.                 err("line %lu: not expecting command", lineno);
  175.             state = KEY;
  176.             command = GET;
  177.             break;
  178.         case 'p':            /* put */
  179.             if (state != COMMAND)
  180.                 err("line %lu: not expecting command", lineno);
  181.             state = KEY;
  182.             command = PUT;
  183.             break;
  184.         case 'r':            /* remove */
  185.             if (state != COMMAND)
  186.                 err("line %lu: not expecting command", lineno);
  187.             state = KEY;
  188.             command = REMOVE;
  189.             break;
  190.         case 's':            /* seq */
  191.             if (state != COMMAND)
  192.                 err("line %lu: not expecting command", lineno);
  193.             if (flags == R_CURSOR) {
  194.                 state = KEY;
  195.                 command = SEQ;
  196.             } else
  197.                 seq(dbp, &key);
  198.             break;
  199.         case 'f':
  200.             flags = setflags(p + 1);
  201.             break;
  202.         case 'D':            /* data file */
  203.             if (state != DATA)
  204.                 err("line %lu: not expecting data", lineno);
  205.             data.data = rfile(p + 1, &data.size);
  206.             goto ldata;
  207.         case 'd':            /* data */
  208.             if (state != DATA)
  209.                 err("line %lu: not expecting data", lineno);
  210.             data.data = xmalloc(p + 1, len - 1);
  211.             data.size = len - 1;
  212. ldata:            switch(command) {
  213.             case COMPARE:
  214.                 compare(&keydata, &data);
  215.                 break;
  216.             case PUT:
  217.                 put(dbp, &key, &data);
  218.                 break;
  219.             default:
  220.                 err("line %lu: command doesn't take data",
  221.                     lineno);
  222.             }
  223.             if (type != DB_RECNO)
  224.                 free(key.data);
  225.             free(data.data);
  226.             state = COMMAND;
  227.             break;
  228.         case 'K':            /* key file */
  229.             if (state != KEY)
  230.                 err("line %lu: not expecting a key", lineno);
  231.             if (type == DB_RECNO)
  232.                 err("line %lu: 'K' not available for recno",
  233.                     lineno);
  234.             key.data = rfile(p + 1, &key.size);
  235.             goto lkey;
  236.         case 'k':            /* key */
  237.             if (state != KEY)
  238.                 err("line %lu: not expecting a key", lineno);
  239.             if (type == DB_RECNO) {
  240.                 static recno_t recno;
  241.                 recno = strtol(p + 1, NULL, 0);
  242.                 key.data = &recno;
  243.                 key.size = sizeof(recno);
  244.             } else {
  245.                 key.data = xmalloc(p + 1, len - 1);
  246.                 key.size = len - 1;
  247.             }
  248. lkey:            switch(command) {
  249.             case COMPARE:
  250.                 getdata(dbp, &key, &keydata);
  251.                 state = DATA;
  252.                 break;
  253.             case GET:
  254.                 get(dbp, &key);
  255.                 if (type != DB_RECNO)
  256.                     free(key.data);
  257.                 state = COMMAND;
  258.                 break;
  259.             case PUT:
  260.                 state = DATA;
  261.                 break;
  262.             case REMOVE:
  263.                 rem(dbp, &key);
  264.                 if (type != DB_RECNO)
  265.                     free(key.data);
  266.                 state = COMMAND;
  267.                 break;
  268.             case SEQ:
  269.                 seq(dbp, &key);
  270.                 if (type != DB_RECNO)
  271.                     free(key.data);
  272.                 state = COMMAND;
  273.                 break;
  274.             default:
  275.                 err("line %lu: command doesn't take a key",
  276.                     lineno);
  277.             }
  278.             break;
  279.         case 'o':
  280.             dump(dbp, p[1] == 'r');
  281.             break;
  282.         default:
  283.             err("line %lu: %s: unknown command character",
  284.                 p, lineno);
  285.         }
  286.     }
  287.     if (dbp->close(dbp))
  288.         err("db->close: %s", strerror(errno));
  289.     (void)close(ofd);
  290.     exit(0);
  291. }
  292.  
  293. #define    NOOVERWRITE    "put failed, would overwrite key\n"
  294. #define    NOSUCHKEY    "get failed, no such key\n"
  295.  
  296. void
  297. compare(db1, db2)
  298.     DBT *db1, *db2;
  299. {
  300.     register size_t len;
  301.     register u_char *p1, *p2;
  302.  
  303.     if (db1->size != db2->size)
  304.         printf("compare failed: key->data len %lu != data len %lu\n",
  305.             db1->size, db2->size);
  306.  
  307.     len = MIN(db1->size, db2->size);
  308.     for (p1 = db1->data, p2 = db2->data; len--;)
  309.         if (*p1++ != *p2++) {
  310.             printf("compare failed at offset %d\n",
  311.                 p1 - (u_char *)db1->data);
  312.             break;
  313.         }
  314. }
  315.  
  316. void
  317. get(dbp, kp)
  318.     DB *dbp;
  319.     DBT *kp;
  320. {
  321.     DBT data;
  322.  
  323.     switch(dbp->get(dbp, kp, &data, flags)) {
  324.     case 0:
  325.         (void)write(ofd, data.data, data.size);
  326.         break;
  327.     case -1:
  328.         err("line %lu: get: %s", lineno, strerror(errno));
  329.         /* NOTREACHED */
  330.     case 1:
  331.         (void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1);
  332.         (void)fprintf(stderr, "%d: %.*s: %s\n", 
  333.             lineno, kp->size, kp->data, NOSUCHKEY);
  334.         break;
  335.     }
  336. }
  337.  
  338. void
  339. getdata(dbp, kp, dp)
  340.     DB *dbp;
  341.     DBT *kp, *dp;
  342. {
  343.     switch(dbp->get(dbp, kp, dp, flags)) {
  344.     case 0:
  345.         return;
  346.     case -1:
  347.         err("line %lu: getdata: %s", lineno, strerror(errno));
  348.         /* NOTREACHED */
  349.     case 1:
  350.         err("line %lu: get failed, no such key", lineno);
  351.         /* NOTREACHED */
  352.     }
  353. }
  354.  
  355. void
  356. put(dbp, kp, dp)
  357.     DB *dbp;
  358.     DBT *kp, *dp;
  359. {
  360.     switch(dbp->put(dbp, kp, dp, flags)) {
  361.     case 0:
  362.         break;
  363.     case -1:
  364.         err("line %lu: put: %s", lineno, strerror(errno));
  365.         /* NOTREACHED */
  366.     case 1:
  367.         (void)write(ofd, NOOVERWRITE, sizeof(NOOVERWRITE) - 1);
  368.         break;
  369.     }
  370. }
  371.  
  372. void
  373. rem(dbp, kp)
  374.     DB *dbp;
  375.     DBT *kp;
  376. {
  377.     switch(dbp->del(dbp, kp, flags)) {
  378.     case 0:
  379.         break;
  380.     case -1:
  381.         err("line %lu: get: %s", lineno, strerror(errno));
  382.         /* NOTREACHED */
  383.     case 1:
  384.         (void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1);
  385.         break;
  386.     }
  387. }
  388.  
  389. void
  390. seq(dbp, kp)
  391.     DB *dbp;
  392.     DBT *kp;
  393. {
  394.     DBT data;
  395.  
  396.     switch(dbp->seq(dbp, kp, &data, flags)) {
  397.     case 0:
  398.         (void)write(ofd, data.data, data.size);
  399.         break;
  400.     case -1:
  401.         err("line %lu: seq: %s", lineno, strerror(errno));
  402.         /* NOTREACHED */
  403.     case 1:
  404.         (void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1);
  405.         break;
  406.     }
  407. }
  408.  
  409. void
  410. dump(dbp, rev)
  411.     DB *dbp;
  412.     int rev;
  413. {
  414.     DBT key, data;
  415.     int flags, nflags;
  416.  
  417.     if (rev) {
  418.         flags = R_LAST;
  419.         nflags = R_PREV;
  420.     } else {
  421.         flags = R_FIRST;
  422.         nflags = R_NEXT;
  423.     }
  424.     for (;; flags = nflags)
  425.         switch(dbp->seq(dbp, &key, &data, flags)) {
  426.         case 0:
  427.             (void)write(ofd, data.data, data.size);
  428.             break;
  429.         case 1:
  430.             goto done;
  431.         case -1:
  432.             err("line %lu: (dump) seq: %s",
  433.                 lineno, strerror(errno));
  434.             /* NOTREACHED */
  435.         }
  436. done:    return;
  437. }
  438.     
  439. u_int
  440. setflags(s)
  441.     char *s;
  442. {
  443.     char *p;
  444.  
  445.     for (; isspace(*s); ++s);
  446.     if (*s == '\n')
  447.         return (0);
  448.     if ((p = index(s, '\n')) != NULL)
  449.         *p = '\0';
  450.     if (!strcmp(s, "R_CURSOR"))
  451.         return (R_CURSOR);
  452.     if (!strcmp(s, "R_FIRST"))
  453.         return (R_FIRST);
  454.     if (!strcmp(s, "R_IAFTER"))
  455.         return (R_IAFTER);
  456.     if (!strcmp(s, "R_IBEFORE"))
  457.         return (R_IBEFORE);
  458.     if (!strcmp(s, "R_LAST"))
  459.         return (R_LAST);
  460.     if (!strcmp(s, "R_NEXT"))
  461.         return (R_NEXT);
  462.     if (!strcmp(s, "R_NOOVERWRITE"))
  463.         return (R_NOOVERWRITE);
  464.     if (!strcmp(s, "R_PREV"))
  465.         return (R_PREV);
  466.     if (!strcmp(s, "R_SETCURSOR"))
  467.         return (R_SETCURSOR);
  468.     err("line %lu: %s: unknown flag", lineno, s);
  469.     /* NOTREACHED */
  470. }
  471.     
  472. DBTYPE
  473. dbtype(s)
  474.     char *s;
  475. {
  476.     if (!strcmp(s, "btree"))
  477.         return (DB_BTREE);
  478.     if (!strcmp(s, "hash"))
  479.         return (DB_HASH);
  480.     if (!strcmp(s, "recno"))
  481.         return (DB_RECNO);
  482.     err("%s: unknown type (use btree, hash or recno)", s);
  483.     /* NOTREACHED */
  484. }
  485.  
  486. void *
  487. setinfo(type, s)
  488.     DBTYPE type;
  489.     char *s;
  490. {
  491.     static BTREEINFO ib;
  492.     static HASHINFO ih;
  493.     static RECNOINFO rh;
  494.     char *eq;
  495.  
  496.     if ((eq = index(s, '=')) == NULL)
  497.         err("%s: illegal structure set statement", s);
  498.     *eq++ = '\0';
  499.     if (!isdigit(*eq))
  500.         err("%s: structure set statement must be a number", s);
  501.         
  502.     switch(type) {
  503.     case DB_BTREE:
  504.         if (!strcmp("flags", s)) {
  505.             ib.flags = strtoul(eq, NULL, 0);
  506.             return (&ib);
  507.         }
  508.         if (!strcmp("cachesize", s)) {
  509.             ib.cachesize = strtoul(eq, NULL, 0);
  510.             return (&ib);
  511.         }
  512.         if (!strcmp("maxkeypage", s)) {
  513.             ib.maxkeypage = strtoul(eq, NULL, 0);
  514.             return (&ib);
  515.         }
  516.         if (!strcmp("minkeypage", s)) {
  517.             ib.minkeypage = strtoul(eq, NULL, 0);
  518.             return (&ib);
  519.         }
  520.         if (!strcmp("lorder", s)) {
  521.             ib.lorder = strtoul(eq, NULL, 0);
  522.             return (&ib);
  523.         }
  524.         if (!strcmp("psize", s)) {
  525.             ib.psize = strtoul(eq, NULL, 0);
  526.             return (&ib);
  527.         }
  528.         break;
  529.     case DB_HASH:
  530.         if (!strcmp("bsize", s)) {
  531.             ih.bsize = strtoul(eq, NULL, 0);
  532.             return (&ih);
  533.         }
  534.         if (!strcmp("ffactor", s)) {
  535.             ih.ffactor = strtoul(eq, NULL, 0);
  536.             return (&ih);
  537.         }
  538.         if (!strcmp("nelem", s)) {
  539.             ih.nelem = strtoul(eq, NULL, 0);
  540.             return (&ih);
  541.         }
  542.         if (!strcmp("cachesize", s)) {
  543.             ih.cachesize = strtoul(eq, NULL, 0);
  544.             return (&ih);
  545.         }
  546.         if (!strcmp("lorder", s)) {
  547.             ih.lorder = strtoul(eq, NULL, 0);
  548.             return (&ih);
  549.         }
  550.         break;
  551.     case DB_RECNO:
  552.         if (!strcmp("flags", s)) {
  553.             rh.flags = strtoul(eq, NULL, 0);
  554.             return (&rh);
  555.         }
  556.         if (!strcmp("cachesize", s)) {
  557.             rh.cachesize = strtoul(eq, NULL, 0);
  558.             return (&rh);
  559.         }
  560.         if (!strcmp("lorder", s)) {
  561.             rh.lorder = strtoul(eq, NULL, 0);
  562.             return (&rh);
  563.         }
  564.         if (!strcmp("reclen", s)) {
  565.             rh.reclen = strtoul(eq, NULL, 0);
  566.             return (&rh);
  567.         }
  568.         if (!strcmp("bval", s)) {
  569.             rh.bval = strtoul(eq, NULL, 0);
  570.             return (&rh);
  571.         }
  572.         if (!strcmp("psize", s)) {
  573.             rh.psize = strtoul(eq, NULL, 0);
  574.             return (&rh);
  575.         }
  576.         break;
  577.     }
  578.     err("%s: unknown structure value", s);
  579.     /* NOTREACHED */
  580. }
  581.  
  582. void *
  583. rfile(name, lenp)
  584.     char *name;
  585.     size_t *lenp;
  586. {
  587.     struct stat sb;
  588.     void *p;
  589.     int fd;
  590.     char *np;
  591.  
  592.     for (; isspace(*name); ++name);
  593.     if ((np = index(name, '\n')) != NULL)
  594.         *np = '\0';
  595.     if ((fd = open(name, O_RDONLY, 0)) < 0 ||
  596.         fstat(fd, &sb))
  597.         err("%s: %s\n", name, strerror(errno));
  598.     if (sb.st_size > (off_t)SIZE_T_MAX)
  599.         err("%s: %s\n", name, strerror(E2BIG));
  600.     if ((p = malloc((u_int)sb.st_size)) == NULL)
  601.         err("%s", strerror(errno));
  602.     (void)read(fd, p, (int)sb.st_size);
  603.     *lenp = sb.st_size;
  604.     (void)close(fd);
  605.     return (p);
  606. }
  607.  
  608. void *
  609. xmalloc(text, len)
  610.     char *text;
  611.     size_t len;
  612. {
  613.     void *p;
  614.  
  615.     if ((p = malloc(len)) == NULL)
  616.         err("%s", strerror(errno));
  617.     memmove(p, text, len);
  618.     return (p);
  619. }
  620.  
  621. void
  622. usage()
  623. {
  624.     (void)fprintf(stderr,
  625.         "usage: dbtest [-f file] [-i info] [-o file] type script\n");
  626.     exit(1);
  627. }
  628.  
  629. #if __STDC__
  630. #include <stdarg.h>
  631. #else
  632. #include <varargs.h>
  633. #endif
  634.  
  635. void
  636. #if __STDC__
  637. err(const char *fmt, ...)
  638. #else
  639. err(fmt, va_alist)
  640.     char *fmt;
  641.         va_dcl
  642. #endif
  643. {
  644.     va_list ap;
  645. #if __STDC__
  646.     va_start(ap, fmt);
  647. #else
  648.     va_start(ap);
  649. #endif
  650.     (void)fprintf(stderr, "dbtest: ");
  651.     (void)vfprintf(stderr, fmt, ap);
  652.     va_end(ap);
  653.     (void)fprintf(stderr, "\n");
  654.     exit(1);
  655.     /* NOTREACHED */
  656. }
  657.