Typo in pp_complement().
[p5sagit/p5-mst-13.2.git] / ext / DB_File / DB_File.xs
index 1223ad4..cb8fd80 100644 (file)
@@ -3,12 +3,12 @@
  DB_File.xs -- Perl 5 interface to Berkeley DB 
 
  written by Paul Marquess <Paul.Marquess@btinternet.com>
- last modified 3rd August 1999
- version 1.69
+ last modified 27th April 2000
+ version 1.73
 
  All comments/suggestions/problems are welcome
 
-     Copyright (c) 1995-9 Paul Marquess. All rights reserved.
+     Copyright (c) 1995-2000 Paul Marquess. All rights reserved.
      This program is free software; you can redistribute it and/or
      modify it under the same terms as Perl itself.
 
         1.69 -  fixed a bug in push -- DB_APPEND wasn't working properly.
                Fixed the R_SETCURSOR bug introduced in 1.68
                Added a new Perl variable $DB_File::db_ver 
-
-
-
+        1.70 -  Initialise $DB_File::db_ver and $DB_File::db_version with 
+               GV_ADD|GV_ADDMULT -- bug spotted by Nick Ing-Simmons.
+               Added a BOOT check to test for equivalent versions of db.h &
+               libdb.a/so.
+        1.71 -  Support for Berkeley DB version 3.
+               Support for Berkeley DB 2/3's backward compatability mode.
+               Rewrote push
+        1.72 -  No change to DB_File.xs
+        1.73 -  No change to DB_File.xs
 
 */
 
 #ifdef op
 #    undef op
 #endif
-#include <db.h>
+
+#ifdef COMPAT185
+#    include <db_185.h>
+#else
+#    include <db.h>
+#endif
 
 #ifndef pTHX
 #    define pTHX
 /* #define TRACE */
 #define DBM_FILTERING
 
+#ifdef TRACE
+#    define Trace(x)        printf x
+#else
+#    define Trace(x)
+#endif
+
 
+#define DBT_clear(x)   Zero(&x, 1, DBT) ;
 
 #ifdef DB_VERSION_MAJOR
 
+#if DB_VERSION_MAJOR == 2
+#    define BERKELEY_DB_1_OR_2
+#endif
+
 /* map version 2 features & constants onto their version 1 equivalent */
 
 #ifdef DB_Prefix_t
 
 /* DBTYPE stays the same */
 /* HASHINFO, RECNOINFO and BTREEINFO  map to DB_INFO */
-typedef DB_INFO        INFO ;
+#if DB_VERSION_MAJOR == 2
+    typedef DB_INFO    INFO ;
+#else /* DB_VERSION_MAJOR > 2 */
+#    define DB_FIXEDLEN        (0x8000)
+#endif /* DB_VERSION_MAJOR == 2 */
 
 /* version 2 has db_recno_t in place of recno_t        */
 typedef db_recno_t     recno_t;
@@ -165,15 +191,18 @@ typedef db_recno_t        recno_t;
 #define R_NEXT          DB_NEXT
 #define R_NOOVERWRITE   DB_NOOVERWRITE
 #define R_PREV          DB_PREV
+
 #if DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR < 5
-#define R_SETCURSOR     0x800000
+#  define R_SETCURSOR  0x800000
 #else
-#define R_SETCURSOR     (-100)
+#  define R_SETCURSOR  (-100)
 #endif
+
 #define R_RECNOSYNC     0
 #define R_FIXEDLEN     DB_FIXEDLEN
 #define R_DUP          DB_DUP
 
+
 #define db_HA_hash     h_hash
 #define db_HA_ffactor  h_ffactor
 #define db_HA_nelem    h_nelem
@@ -208,13 +237,15 @@ typedef db_recno_t        recno_t;
 #define DB_flags(x, v) x |= v 
 
 #if DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR < 5
-#define flagSet(flags, bitmask)        ((flags) & (bitmask))
+#    define flagSet(flags, bitmask)    ((flags) & (bitmask))
 #else
-#define flagSet(flags, bitmask)        (((flags) & DB_OPFLAGS_MASK) == (bitmask))
+#    define flagSet(flags, bitmask)    (((flags) & DB_OPFLAGS_MASK) == (bitmask))
 #endif
 
 #else /* db version 1.x */
 
+#define BERKELEY_DB_1_OR_2
+
 typedef union INFO {
         HASHINFO       hash ;
         RECNOINFO      recno ;
@@ -223,17 +254,17 @@ typedef union INFO {
 
 
 #ifdef mDB_Prefix_t 
-#ifdef DB_Prefix_t
-#undef DB_Prefix_t
-#endif
-#define DB_Prefix_t    mDB_Prefix_t 
+#  ifdef DB_Prefix_t
+#    undef DB_Prefix_t
+#  endif
+#  define DB_Prefix_t  mDB_Prefix_t 
 #endif
 
 #ifdef mDB_Hash_t
-#ifdef DB_Hash_t
-#undef DB_Hash_t
-#endif
-#define DB_Hash_t      mDB_Hash_t
+#  ifdef DB_Hash_t
+#    undef DB_Hash_t
+#  endif
+#  define DB_Hash_t    mDB_Hash_t
 #endif
 
 #define db_HA_hash     hash.hash
@@ -280,20 +311,20 @@ typedef union INFO {
 
 #ifdef DB_VERSION_MAJOR
 #define db_DESTROY(db)                  ( db->cursor->c_close(db->cursor),\
-                                         db->dbp->close(db->dbp, 0) )
+                                         (db->dbp->close)(db->dbp, 0) )
 #define db_close(db)                   ((db->dbp)->close)(db->dbp, 0)
 #define db_del(db, key, flags)          (flagSet(flags, R_CURSOR)                                      \
                                                ? ((db->cursor)->c_del)(db->cursor, 0)          \
                                                : ((db->dbp)->del)(db->dbp, NULL, &key, flags) )
 
-#else
+#else /* ! DB_VERSION_MAJOR */
 
 #define db_DESTROY(db)                  ((db->dbp)->close)(db->dbp)
 #define db_close(db)                   ((db->dbp)->close)(db->dbp)
 #define db_del(db, key, flags)          ((db->dbp)->del)(db->dbp, &key, flags)
 #define db_put(db, key, value, flags)   ((db->dbp)->put)(db->dbp, &key, &value, flags)
 
-#endif
+#endif /* ! DB_VERSION_MAJOR */
 
 
 #define db_seq(db, key, value, flags)   do_SEQ(db, key, value, flags)
@@ -305,7 +336,9 @@ typedef struct {
        SV *    prefix ;
        SV *    hash ;
        int     in_memory ;
+#ifdef BERKELEY_DB_1_OR_2
        INFO    info ;
+#endif 
 #ifdef DB_VERSION_MAJOR
        DBC *   cursor ;
 #endif
@@ -438,41 +471,6 @@ u_int              flags ;
 
 #endif /* DB_VERSION_MAJOR */
 
-static void
-GetVersionInfo(pTHX)
-{
-    SV * version_sv = perl_get_sv("DB_File::db_version", TRUE) ;
-    SV * ver_sv = perl_get_sv("DB_File::db_ver", TRUE) ;
-#ifdef DB_VERSION_MAJOR
-    int Major, Minor, Patch ;
-
-    (void)db_version(&Major, &Minor, &Patch) ;
-
-    /* check that libdb is recent enough  -- we need 2.3.4 or greater */
-    if (Major == 2 && (Minor < 3 || (Minor ==  3 && Patch < 4)))
-       croak("DB_File needs Berkeley DB 2.3.4 or greater, you have %d.%d.%d\n",
-                Major, Minor, Patch) ;
-#if PERL_VERSION > 3
-    sv_setpvf(version_sv, "%d.%d", Major, Minor) ;
-    sv_setpvf(ver_sv, "%d.%03d%03d", Major, Minor, Patch) ;
-#else
-    {
-        char buffer[40] ;
-        sprintf(buffer, "%d.%d", Major, Minor) ;
-        sv_setpv(version_sv, buffer) ; 
-        sprintf(buffer, "%d.%03d%03d", Major, Minor, Patch) ;
-        sv_setpv(ver_sv, buffer) ; 
-    }
-#endif
-#else
-    sv_setiv(version_sv, 1) ;
-    sv_setiv(ver_sv, 1) ;
-#endif
-
-}
-
 
 static int
 #ifdef CAN_PROTOTYPE
@@ -633,7 +631,7 @@ size_t size ;
 }
 
 
-#ifdef TRACE
+#if defined(TRACE) && defined(BERKELEY_DB_1_OR_2)
 
 static void
 #ifdef CAN_PROTOTYPE
@@ -716,8 +714,8 @@ DB_File db ;
     DBT                value ;
     int                RETVAL ;
 
-    DBT_flags(key) ;
-    DBT_flags(value) ;
+    DBT_clear(key) ;
+    DBT_clear(value) ;
     RETVAL = do_SEQ(db, key, value, R_LAST) ;
     if (RETVAL == 0)
         RETVAL = *(I32 *)key.data ;
@@ -752,6 +750,7 @@ I32      value ;
     return value ;
 }
 
+
 static DB_File
 #ifdef CAN_PROTOTYPE
 ParseOpenInfo(pTHX_ int isHASH, char *name, int flags, int mode, SV *sv)
@@ -764,6 +763,9 @@ int    mode ;
 SV *   sv ;
 #endif
 {
+
+#ifdef BERKELEY_DB_1_OR_2 /* Berkeley DB Version 1  or 2 */
+
     SV **      svp;
     HV *       action ;
     DB_File    RETVAL = (DB_File)safemalloc(sizeof(DB_File_type)) ;
@@ -1024,11 +1026,265 @@ SV *   sv ;
 
     }
 #else
+
+#if defined(DB_LIBRARY_COMPATIBILITY_API) && DB_VERSION_MAJOR > 2
+    RETVAL->dbp = __db185_open(name, flags, mode, RETVAL->type, openinfo) ; 
+#else    
     RETVAL->dbp = dbopen(name, flags, mode, RETVAL->type, openinfo) ; 
+#endif /* DB_LIBRARY_COMPATIBILITY_API */
+
 #endif
 
     return (RETVAL) ;
-}
+
+#else /* Berkeley DB Version > 2 */
+
+    SV **      svp;
+    HV *       action ;
+    DB_File    RETVAL = (DB_File)safemalloc(sizeof(DB_File_type)) ;
+    DB *       dbp ;
+    STRLEN     n_a;
+    int                status ;
+
+/* printf("In ParseOpenInfo name=[%s] flags=[%d] mode = [%d]\n", name, flags, mode) ;  */
+    Zero(RETVAL, 1, DB_File_type) ;
+
+    /* Default to HASH */
+#ifdef DBM_FILTERING
+    RETVAL->filtering = 0 ;
+    RETVAL->filter_fetch_key = RETVAL->filter_store_key = 
+    RETVAL->filter_fetch_value = RETVAL->filter_store_value =
+#endif /* DBM_FILTERING */
+    RETVAL->hash = RETVAL->compare = RETVAL->prefix = NULL ;
+    RETVAL->type = DB_HASH ;
+
+     /* DGH - Next line added to avoid SEGV on existing hash DB */
+    CurrentDB = RETVAL; 
+
+    /* fd for 1.86 hash in memory files doesn't return -1 like 1.85 */
+    RETVAL->in_memory = (name == NULL) ;
+
+    status = db_create(&RETVAL->dbp, NULL,0) ;
+    /* printf("db_create returned %d %s\n", status, db_strerror(status)) ; */
+    if (status) {
+       RETVAL->dbp = NULL ;
+        return (RETVAL) ;
+    }  
+    dbp = RETVAL->dbp ;
+
+    if (sv)
+    {
+        if (! SvROK(sv) )
+            croak ("type parameter is not a reference") ;
+
+        svp  = hv_fetch( (HV*)SvRV(sv), "GOT", 3, FALSE) ;
+        if (svp && SvOK(*svp))
+            action  = (HV*) SvRV(*svp) ;
+       else
+           croak("internal error") ;
+
+        if (sv_isa(sv, "DB_File::HASHINFO"))
+        {
+
+           if (!isHASH)
+               croak("DB_File can only tie an associative array to a DB_HASH database") ;
+
+            RETVAL->type = DB_HASH ;
+  
+            svp = hv_fetch(action, "hash", 4, FALSE); 
+
+            if (svp && SvOK(*svp))
+            {
+               (void)dbp->set_h_hash(dbp, hash_cb) ;
+               RETVAL->hash = newSVsv(*svp) ;
+            }
+
+           svp = hv_fetch(action, "ffactor", 7, FALSE);
+          if (svp)
+              (void)dbp->set_h_ffactor(dbp, SvIV(*svp)) ;
+         
+           svp = hv_fetch(action, "nelem", 5, FALSE);
+          if (svp)
+               (void)dbp->set_h_nelem(dbp, SvIV(*svp)) ;
+         
+           svp = hv_fetch(action, "bsize", 5, FALSE);
+          if (svp)
+               (void)dbp->set_pagesize(dbp, SvIV(*svp));
+           
+           svp = hv_fetch(action, "cachesize", 9, FALSE);
+          if (svp)
+               (void)dbp->set_cachesize(dbp, 0, SvIV(*svp), 0) ;
+         
+           svp = hv_fetch(action, "lorder", 6, FALSE);
+          if (svp)
+               (void)dbp->set_lorder(dbp, SvIV(*svp)) ;
+
+           PrintHash(info) ; 
+        }
+        else if (sv_isa(sv, "DB_File::BTREEINFO"))
+        {
+           if (!isHASH)
+               croak("DB_File can only tie an associative array to a DB_BTREE database");
+
+            RETVAL->type = DB_BTREE ;
+   
+            svp = hv_fetch(action, "compare", 7, FALSE);
+            if (svp && SvOK(*svp))
+            {
+                (void)dbp->set_bt_compare(dbp, btree_compare) ;
+               RETVAL->compare = newSVsv(*svp) ;
+            }
+
+            svp = hv_fetch(action, "prefix", 6, FALSE);
+            if (svp && SvOK(*svp))
+            {
+                (void)dbp->set_bt_prefix(dbp, btree_prefix) ;
+               RETVAL->prefix = newSVsv(*svp) ;
+            }
+
+           svp = hv_fetch(action, "flags", 5, FALSE);
+          if (svp)
+              (void)dbp->set_flags(dbp, SvIV(*svp)) ;
+   
+           svp = hv_fetch(action, "cachesize", 9, FALSE);
+          if (svp)
+               (void)dbp->set_cachesize(dbp, 0, SvIV(*svp), 0) ;
+         
+           svp = hv_fetch(action, "psize", 5, FALSE);
+          if (svp)
+               (void)dbp->set_pagesize(dbp, SvIV(*svp)) ;
+         
+           svp = hv_fetch(action, "lorder", 6, FALSE);
+          if (svp)
+               (void)dbp->set_lorder(dbp, SvIV(*svp)) ;
+
+            PrintBtree(info) ;
+         
+        }
+        else if (sv_isa(sv, "DB_File::RECNOINFO"))
+        {
+           int fixed = FALSE ;
+
+           if (isHASH)
+               croak("DB_File can only tie an array to a DB_RECNO database");
+
+            RETVAL->type = DB_RECNO ;
+
+           svp = hv_fetch(action, "flags", 5, FALSE);
+          if (svp) {
+               int flags = SvIV(*svp) ;
+               /* remove FIXDLEN, if present */
+               if (flags & DB_FIXEDLEN) {
+                   fixed = TRUE ;
+                   flags &= ~DB_FIXEDLEN ;
+               }
+          }
+
+           svp = hv_fetch(action, "cachesize", 9, FALSE);
+          if (svp) {
+               status = dbp->set_cachesize(dbp, 0, SvIV(*svp), 0) ;
+          }
+         
+           svp = hv_fetch(action, "psize", 5, FALSE);
+          if (svp) {
+               status = dbp->set_pagesize(dbp, SvIV(*svp)) ;
+           }
+         
+           svp = hv_fetch(action, "lorder", 6, FALSE);
+          if (svp) {
+               status = dbp->set_lorder(dbp, SvIV(*svp)) ;
+          }
+
+           svp = hv_fetch(action, "bval", 4, FALSE);
+            if (svp && SvOK(*svp))
+            {
+               int value ;
+                if (SvPOK(*svp))
+                   value = (int)*SvPV(*svp, n_a) ;
+               else
+                   value = SvIV(*svp) ;
+
+               if (fixed) {
+                   status = dbp->set_re_pad(dbp, value) ;
+               }
+               else {
+                   status = dbp->set_re_delim(dbp, value) ;
+               }
+
+            }
+
+          if (fixed) {
+               svp = hv_fetch(action, "reclen", 6, FALSE);
+              if (svp) {
+                  u_int32_t len =  (u_int32_t)SvIV(*svp) ;
+                   status = dbp->set_re_len(dbp, len) ;
+              }    
+          }
+         
+           if (name != NULL) {
+               status = dbp->set_re_source(dbp, name) ;
+               name = NULL ;
+           }   
+
+            svp = hv_fetch(action, "bfname", 6, FALSE); 
+            if (svp && SvOK(*svp)) {
+               char * ptr = SvPV(*svp,n_a) ;
+               name = (char*) n_a ? ptr : NULL ;
+           }
+           else
+               name = NULL ;
+         
+
+           status = dbp->set_flags(dbp, DB_RENUMBER) ;
+         
+               if (flags){
+                   (void)dbp->set_flags(dbp, flags) ;
+               }
+            PrintRecno(info) ;
+        }
+        else
+            croak("type is not of type DB_File::HASHINFO, DB_File::BTREEINFO or DB_File::RECNOINFO");
+    }
+
+    {
+        int            Flags = 0 ;
+        int            status ;
+
+        /* Map 1.x flags to 3.x flags */
+        if ((flags & O_CREAT) == O_CREAT)
+            Flags |= DB_CREATE ;
+
+#if O_RDONLY == 0
+        if (flags == O_RDONLY)
+#else
+        if ((flags & O_RDONLY) == O_RDONLY && (flags & O_RDWR) != O_RDWR)
+#endif
+            Flags |= DB_RDONLY ;
+
+#ifdef O_TRUNC
+        if ((flags & O_TRUNC) == O_TRUNC)
+            Flags |= DB_TRUNCATE ;
+#endif
+
+        status = RETVAL->dbp->open(RETVAL->dbp, name, NULL, RETVAL->type, 
+                               Flags, mode) ; 
+       /* printf("open returned %d %s\n", status, db_strerror(status)) ; */
+
+        if (status == 0)
+            status = (RETVAL->dbp->cursor)(RETVAL->dbp, NULL, &RETVAL->cursor,
+                       0) ;
+       /* printf("cursor returned %d %s\n", status, db_strerror(status)) ; */
+
+        if (status)
+           RETVAL->dbp = NULL ;
+
+    }
+
+    return (RETVAL) ;
+
+#endif /* Berkeley DB Version > 2 */
+
+} /* ParseOpenInfo */
 
 
 static double 
@@ -1271,11 +1527,11 @@ MODULE = DB_File        PACKAGE = DB_File       PREFIX = db_
 
 BOOT:
   {
-    GetVersionInfo(aTHX) ;
+    __getBerkeleyDBInfo() ;
  
+    DBT_clear(empty) ; 
     empty.data = &zero ;
     empty.size =  sizeof(recno_t) ;
-    DBT_flags(empty) ; 
   }
 
 double
@@ -1331,7 +1587,7 @@ db_DESTROY(db)
          if (db->filter_store_value)
            SvREFCNT_dec(db->filter_store_value) ;
 #endif /* DBM_FILTERING */
-         Safefree(db) ;
+         safefree(db) ;
 #ifdef DB_VERSION_MAJOR
          if (RETVAL > 0)
            RETVAL = -1 ;
@@ -1355,7 +1611,7 @@ db_EXISTS(db, key)
        {
           DBT          value ;
        
-         DBT_flags(value) ; 
+         DBT_clear(value) ; 
          CurrentDB = db ;
          RETVAL = (((db->dbp)->get)(db->dbp, TXN &key, &value, 0) == 0) ;
        }
@@ -1371,7 +1627,7 @@ db_FETCH(db, key, flags=0)
        {
             DBT                value ;
 
-           DBT_flags(value) ; 
+           DBT_clear(value) ; 
            CurrentDB = db ;
            /* RETVAL = ((db->dbp)->get)(db->dbp, TXN &key, &value, flags) ; */
            RETVAL = db_get(db, key, value, flags) ;
@@ -1397,8 +1653,8 @@ db_FIRSTKEY(db)
            DBTKEY      key ;
            DBT         value ;
 
-           DBT_flags(key) ; 
-           DBT_flags(value) ; 
+           DBT_clear(key) ; 
+           DBT_clear(value) ; 
            CurrentDB = db ;
            RETVAL = do_SEQ(db, key, value, R_FIRST) ;
            ST(0) = sv_newmortal();
@@ -1413,7 +1669,7 @@ db_NEXTKEY(db, key)
        {
            DBT         value ;
 
-           DBT_flags(value) ; 
+           DBT_clear(value) ; 
            CurrentDB = db ;
            RETVAL = do_SEQ(db, key, value, R_NEXT) ;
            ST(0) = sv_newmortal();
@@ -1437,8 +1693,8 @@ unshift(db, ...)
            DB *        Db = db->dbp ;
            STRLEN      n_a;
 
-           DBT_flags(key) ; 
-           DBT_flags(value) ; 
+           DBT_clear(key) ; 
+           DBT_clear(value) ; 
            CurrentDB = db ;
 #ifdef DB_VERSION_MAJOR
            /* get the first value */
@@ -1475,8 +1731,8 @@ pop(db)
            DBTKEY      key ;
            DBT         value ;
 
-           DBT_flags(key) ; 
-           DBT_flags(value) ; 
+           DBT_clear(key) ; 
+           DBT_clear(value) ; 
            CurrentDB = db ;
 
            /* First get the final value */
@@ -1502,8 +1758,8 @@ shift(db)
            DBT         value ;
            DBTKEY      key ;
 
-           DBT_flags(key) ; 
-           DBT_flags(value) ; 
+           DBT_clear(key) ; 
+           DBT_clear(value) ; 
            CurrentDB = db ;
            /* get the first value */
            RETVAL = do_SEQ(db, key, value, R_FIRST) ;   
@@ -1531,45 +1787,37 @@ push(db, ...)
            DB *        Db = db->dbp ;
            int         i ;
            STRLEN      n_a;
+           int         keyval ;
 
            DBT_flags(key) ; 
            DBT_flags(value) ; 
            CurrentDB = db ;
-#ifdef DB_VERSION_MAJOR
-               RETVAL = do_SEQ(db, key, value, DB_LAST) ;
-               RETVAL = 0 ;
-               key = empty ;
-               for (i = 1 ; i < items  ; ++i)
-               {
-                   value.data = SvPV(ST(i), n_a) ;
-                   value.size = n_a ;
-                   RETVAL = (Db->put)(Db, NULL, &key, &value, DB_APPEND) ;
-                   if (RETVAL != 0)
-                       break;
-               }
-#else          
-           
            /* Set the Cursor to the Last element */
            RETVAL = do_SEQ(db, key, value, R_LAST) ;
+#ifndef DB_VERSION_MAJOR                                   
            if (RETVAL >= 0)
+#endif     
            {
-               if (RETVAL == 1)
-                   key = empty ;
-               for (i = items - 1 ; i > 0 ; --i)
+               if (RETVAL == 0)
+                   keyval = *(int*)key.data ;
+               else
+                   keyval = 0 ;
+               for (i = 1 ; i < items ; ++i)
                {
                    value.data = SvPV(ST(i), n_a) ;
                    value.size = n_a ;
-                   RETVAL = (Db->put)(Db, &key, &value, R_IAFTER) ;
+                   ++ keyval ;
+                   key.data = &keyval ;
+                   key.size = sizeof(int) ;
+                   RETVAL = (Db->put)(Db, TXN &key, &value, 0) ;
                    if (RETVAL != 0)
                        break;
                }
            }
-#endif
        }
        OUTPUT:
            RETVAL
 
-
 I32
 length(db)
        DB_File         db
@@ -1611,7 +1859,7 @@ db_get(db, key, value, flags=0)
        u_int           flags
        CODE:
          CurrentDB = db ;
-         DBT_flags(value) ; 
+         DBT_clear(value) ; 
          RETVAL = db_get(db, key, value, flags) ;
 #ifdef DB_VERSION_MAJOR
          if (RETVAL > 0)
@@ -1686,7 +1934,7 @@ db_seq(db, key, value, flags)
        u_int           flags
        CODE:
          CurrentDB = db ;
-         DBT_flags(value) ; 
+         DBT_clear(value) ; 
          RETVAL = db_seq(db, key, value, flags);
 #ifdef DB_VERSION_MAJOR
          if (RETVAL > 0)