DB_File 1.64 patch
[p5sagit/p5-mst-13.2.git] / ext / DB_File / DB_File.xs
index 8f2eda1..540fa9c 100644 (file)
@@ -2,13 +2,13 @@
 
  DB_File.xs -- Perl 5 interface to Berkeley DB 
 
- written by Paul Marquess (pmarquess@bfsec.bt.co.uk)
- last modified 20th Nov 1997
- version 1.56
+ written by Paul Marquess <Paul.Marquess@btinternet.com>
+ last modified 21st February 1999
+ version 1.64
 
  All comments/suggestions/problems are welcome
 
-     Copyright (c) 1995, 1996, 1997 Paul Marquess. All rights reserved.
+     Copyright (c) 1995-9 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.54 -  Fixed bug in the fd method
         1.55 -  Fix for AIX from Jarkko Hietaniemi
         1.56 -  No change to DB_File.xs
+        1.57 -  added the #undef op to allow building with Threads support.
+       1.58 -  Fixed a problem with the use of sv_setpvn. When the
+               size is specified as 0, it does a strlen on the data.
+               This was ok for DB 1.x, but isn't for DB 2.x.
+        1.59 -  No change to DB_File.xs
+        1.60 -  Some code tidy up
+        1.61 -  added flagSet macro for DB 2.5.x
+               fixed typo in O_RDONLY test.
+        1.62 -  No change to DB_File.xs
+        1.63 -  Fix to alllow DB 2.6.x to build.
+        1.64 -  Tidied up the 1.x to 2.x flags mapping code.
+               Added a patch from Mark Kettenis <kettenis@wins.uva.nl>
+               to fix a flag mapping problem with O_RDONLY on the Hurd
 
 
 
 #include "perl.h"
 #include "XSUB.h"
 
+#ifndef PERL_VERSION
+#include "patchlevel.h"
+#define PERL_REVISION  5
+#define PERL_VERSION   PATCHLEVEL
+#define PERL_SUBVERSION        SUBVERSION
+#endif
+
+#if PERL_REVISION == 5 && (PERL_VERSION < 4 || (PERL_VERSION == 4 && PERL_SUBVERSION <= 75 ))
+
+#    define PL_sv_undef                sv_undef
+#    define PL_na              na
+
+#endif
+
 /* Being the Berkeley DB we prefer the <sys/cdefs.h> (which will be
  * shortly #included by the <db.h>) __attribute__ to the possibly
  * already defined __attribute__, for example by GNUC or by Perl. */
 
 #undef __attribute__
 
+/* If Perl has been compiled with Threads support,the symbol op will
+   be defined here. This clashes with a field name in db.h, so get rid of it.
+ */
+#ifdef op
+#undef op
+#endif
 #include <db.h>
 
 #include <fcntl.h> 
@@ -141,6 +174,12 @@ typedef db_recno_t recno_t;
 #define DBT_flags(x)   x.flags = 0
 #define DB_flags(x, v) x |= v 
 
+#if DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR < 5
+#define flagSet(flags, bitmask)        ((flags) & (bitmask))
+#else
+#define flagSet(flags, bitmask)        (((flags) & DB_OPFLAGS_MASK) == (bitmask))
+#endif
+
 #else /* db version 1.x */
 
 typedef union INFO {
@@ -193,6 +232,7 @@ typedef union INFO {
 #define do_SEQ(db, key, value, flag)   (db->dbp->seq)(db->dbp, &key, &value, flag)
 #define DBT_flags(x)   
 #define DB_flags(x, v) 
+#define flagSet(flags, bitmask)        ((flags) & (bitmask))
 
 #endif /* db version 1 */
 
@@ -204,10 +244,11 @@ typedef union INFO {
 
 #define db_sync(db, flags)              ((db->dbp)->sync)(db->dbp, flags)
 #define db_get(db, key, value, flags)   ((db->dbp)->get)(db->dbp, TXN &key, &value, flags)
+
 #ifdef DB_VERSION_MAJOR
 #define db_DESTROY(db)                  ((db->dbp)->close)(db->dbp, 0)
 #define db_close(db)                   ((db->dbp)->close)(db->dbp, 0)
-#define db_del(db, key, flags)          ((flags & R_CURSOR)                                    \
+#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) )
 
@@ -220,6 +261,7 @@ typedef union INFO {
 
 #endif
 
+
 #define db_seq(db, key, value, flags)   do_SEQ(db, key, value, flags)
 
 typedef struct {
@@ -238,10 +280,11 @@ typedef struct {
 typedef DB_File_type * DB_File ;
 typedef DBT DBTKEY ;
 
+#define my_sv_setpvn(sv, d, s) sv_setpvn(sv, (s ? d : (void*)""), s)
 
 #define OutputValue(arg, name)                                 \
        { if (RETVAL == 0) {                                    \
-             sv_setpvn(arg, name.data, name.size) ;            \
+             my_sv_setpvn(arg, name.data, name.size) ;         \
          }                                                     \
        }
 
@@ -249,13 +292,14 @@ typedef DBT DBTKEY ;
        { if (RETVAL == 0)                                      \
          {                                                     \
                if (db->type != DB_RECNO) {                     \
-                   sv_setpvn(arg, name.data, name.size);       \
+                   my_sv_setpvn(arg, name.data, name.size);    \
                }                                               \
                else                                            \
                    sv_setiv(arg, (I32)*(I32*)name.data - 1);   \
          }                                                     \
        }
 
+
 /* Internal Global Data */
 static recno_t Value ; 
 static recno_t zero = 0 ;
@@ -274,12 +318,17 @@ u_int             flags ;
 {
     int status ;
 
-    if (flags & R_CURSOR) {
+    if (flagSet(flags, R_CURSOR)) {
        status = ((db->cursor)->c_del)(db->cursor, 0);
        if (status != 0)
            return status ;
 
+#if DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR < 5
        flags &= ~R_CURSOR ;
+#else
+       flags &= ~DB_OPFLAGS_MASK ;
+#endif
+
     }
 
     return ((db->dbp)->put)(db->dbp, NULL, &key, &value, flags) ;
@@ -302,7 +351,7 @@ GetVersionInfo()
        croak("DB_File needs Berkeley DB 2.0.5 or greater, you have %d.%d.%d\n",
                 Major, Minor, Patch) ;
  
-#if PATCHLEVEL > 3
+#if PERL_VERSION > 3
     sv_setpvf(ver_sv, "%d.%d", Major, Minor) ;
 #else
     {
@@ -344,8 +393,8 @@ const DBT * key2 ;
     ENTER ;
     SAVETMPS;
 
-    PUSHMARK(sp) ;
-    EXTEND(sp,2) ;
+    PUSHMARK(SP) ;
+    EXTEND(SP,2) ;
     PUSHs(sv_2mortal(newSVpv(data1,key1->size)));
     PUSHs(sv_2mortal(newSVpv(data2,key2->size)));
     PUTBACK ;
@@ -391,8 +440,8 @@ const DBT * key2 ;
     ENTER ;
     SAVETMPS;
 
-    PUSHMARK(sp) ;
-    EXTEND(sp,2) ;
+    PUSHMARK(SP) ;
+    EXTEND(SP,2) ;
     PUSHs(sv_2mortal(newSVpv(data1,key1->size)));
     PUSHs(sv_2mortal(newSVpv(data2,key2->size)));
     PUTBACK ;
@@ -429,7 +478,7 @@ size_t size ;
     ENTER ;
     SAVETMPS;
 
-    PUSHMARK(sp) ;
+    PUSHMARK(SP) ;
 
     XPUSHs(sv_2mortal(newSVpv((char*)data,size)));
     PUTBACK ;
@@ -560,13 +609,13 @@ SV *   sv ;
 {
     SV **      svp;
     HV *       action ;
-    DB_File    RETVAL;
+    DB_File    RETVAL = (DB_File)safemalloc(sizeof(DB_File_type)) ;
     void *     openinfo = NULL ;
-    INFO       * info;
+    INFO       * info  = &RETVAL->info ;
+    STRLEN     n_a;
 
 /* printf("In ParseOpenInfo name=[%s] flags=[%d] mode = [%d]\n", name, flags, mode) ;  */
-    Newz(777, RETVAL, 1, DB_File_type) ;
-    info  = &RETVAL->info ;
+    Zero(RETVAL, 1, DB_File_type) ;
 
     /* Default to HASH */
     RETVAL->hash = RETVAL->compare = RETVAL->prefix = NULL ;
@@ -705,11 +754,11 @@ SV *   sv ;
 #endif
             svp = hv_fetch(action, "bfname", 6, FALSE); 
             if (svp && SvOK(*svp)) {
-               char * ptr = SvPV(*svp,na) ;
+               char * ptr = SvPV(*svp,n_a) ;
 #ifdef DB_VERSION_MAJOR
-               name = (char*) na ? ptr : NULL ;
+               name = (char*) n_a ? ptr : NULL ;
 #else
-                info->db_RE_bfname = (char*) (na ? ptr : NULL) ;
+                info->db_RE_bfname = (char*) (n_a ? ptr : NULL) ;
 #endif
            }
            else
@@ -725,7 +774,7 @@ SV *   sv ;
             {
                int value ;
                 if (SvPOK(*svp))
-                   value = (int)*SvPV(*svp, na) ;
+                   value = (int)*SvPV(*svp, n_a) ;
                else
                    value = SvIV(*svp) ;
 
@@ -743,7 +792,7 @@ SV *   sv ;
             if (svp && SvOK(*svp))
             {
                 if (SvPOK(*svp))
-                   info->db_RE_bval = (u_char)*SvPV(*svp, na) ;
+                   info->db_RE_bval = (u_char)*SvPV(*svp, n_a) ;
                else
                    info->db_RE_bval = (u_char)(unsigned long) SvIV(*svp) ;
                DB_flags(info->flags, DB_DELIMITER) ;
@@ -787,26 +836,26 @@ SV *   sv ;
         if ((flags & O_CREAT) == O_CREAT)
             Flags |= DB_CREATE ;
 
-#ifdef O_NONBLOCK
-        if ((flags & O_NONBLOCK) == O_NONBLOCK)
-            Flags |= DB_EXCL ;
-#endif
-
 #if O_RDONLY == 0
         if (flags == O_RDONLY)
 #else
-        if (flags & O_RDONLY) == O_RDONLY)
+        if ((flags & O_RDONLY) == O_RDONLY && (flags & O_RDWR) != O_RDWR)
 #endif
             Flags |= DB_RDONLY ;
 
-#ifdef O_NONBLOCK
+#ifdef O_TRUNC
         if ((flags & O_TRUNC) == O_TRUNC)
             Flags |= DB_TRUNCATE ;
 #endif
 
         status = db_open(name, RETVAL->type, Flags, mode, NULL, openinfo, &RETVAL->dbp) ; 
         if (status == 0)
+#if DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR < 6
             status = (RETVAL->dbp->cursor)(RETVAL->dbp, NULL, &RETVAL->cursor) ;
+#else
+            status = (RETVAL->dbp->cursor)(RETVAL->dbp, NULL, &RETVAL->cursor,
+                       0) ;
+#endif
 
         if (status)
            RETVAL->dbp = NULL ;
@@ -1087,9 +1136,10 @@ db_DoTie_(isHASH, dbtype, name=undef, flags=O_CREAT|O_RDWR, mode=0666, type=DB_H
        {
            char *      name = (char *) NULL ; 
            SV *        sv = (SV *) NULL ; 
+           STRLEN      n_a;
 
            if (items >= 3 && SvOK(ST(2))) 
-               name = (char*) SvPV(ST(2), na) ; 
+               name = (char*) SvPV(ST(2), n_a) ; 
 
             if (items == 6)
                sv = ST(5) ;
@@ -1158,8 +1208,7 @@ db_FETCH(db, key, flags=0)
            /* RETVAL = ((db->dbp)->get)(db->dbp, TXN &key, &value, flags) ; */
            RETVAL = db_get(db, key, value, flags) ;
            ST(0) = sv_newmortal();
-           if (RETVAL == 0) 
-               sv_setpvn(ST(0), value.data, value.size);
+           OutputValue(ST(0), value)
        }
 
 int
@@ -1186,13 +1235,7 @@ db_FIRSTKEY(db)
            CurrentDB = db ;
            RETVAL = do_SEQ(db, key, value, R_FIRST) ;
            ST(0) = sv_newmortal();
-           if (RETVAL == 0)
-           {
-               if (db->type != DB_RECNO)
-                   sv_setpvn(ST(0), key.data, key.size);
-               else
-                   sv_setiv(ST(0), (I32)*(I32*)key.data - 1);
-           }
+           OutputKey(ST(0), key) ;
        }
 
 int
@@ -1208,13 +1251,7 @@ db_NEXTKEY(db, key)
            CurrentDB = db ;
            RETVAL = do_SEQ(db, key, value, R_NEXT) ;
            ST(0) = sv_newmortal();
-           if (RETVAL == 0)
-           {
-               if (db->type != DB_RECNO)
-                   sv_setpvn(ST(0), key.data, key.size);
-               else
-                   sv_setiv(ST(0), (I32)*(I32*)key.data - 1);
-           }
+           OutputKey(ST(0), key) ;
        }
 
 #
@@ -1224,6 +1261,7 @@ db_NEXTKEY(db, key)
 int
 unshift(db, ...)
        DB_File         db
+       ALIAS:          UNSHIFT = 1
        CODE:
        {
            DBTKEY      key ;
@@ -1231,6 +1269,7 @@ unshift(db, ...)
            int         i ;
            int         One ;
            DB *        Db = db->dbp ;
+           STRLEN      n_a;
 
            DBT_flags(key) ; 
            DBT_flags(value) ; 
@@ -1244,8 +1283,8 @@ unshift(db, ...)
 #endif
            for (i = items-1 ; i > 0 ; --i)
            {
-               value.data = SvPV(ST(i), na) ;
-               value.size = na ;
+               value.data = SvPV(ST(i), n_a) ;
+               value.size = n_a ;
                One = 1 ;
                key.data = &One ;
                key.size = sizeof(int) ;
@@ -1264,6 +1303,7 @@ unshift(db, ...)
 I32
 pop(db)
        DB_File         db
+       ALIAS:          POP = 1
        CODE:
        {
            DBTKEY      key ;
@@ -1281,16 +1321,17 @@ pop(db)
            if (RETVAL == 0)
            {
                /* the call to del will trash value, so take a copy now */
-               sv_setpvn(ST(0), value.data, value.size);
+               OutputValue(ST(0), value) ;
                RETVAL = db_del(db, key, R_CURSOR) ;
                if (RETVAL != 0) 
-                   sv_setsv(ST(0), &sv_undef); 
+                   sv_setsv(ST(0), &PL_sv_undef); 
            }
        }
 
 I32
 shift(db)
        DB_File         db
+       ALIAS:          SHIFT = 1
        CODE:
        {
            DBT         value ;
@@ -1307,10 +1348,10 @@ shift(db)
            if (RETVAL == 0)
            {
                /* the call to del will trash value, so take a copy now */
-               sv_setpvn(ST(0), value.data, value.size);
+               OutputValue(ST(0), value) ;
                RETVAL = db_del(db, key, R_CURSOR) ;
                if (RETVAL != 0)
-                   sv_setsv (ST(0), &sv_undef) ;
+                   sv_setsv (ST(0), &PL_sv_undef) ;
            }
        }
 
@@ -1318,6 +1359,7 @@ shift(db)
 I32
 push(db, ...)
        DB_File         db
+       ALIAS:          PUSH = 1
        CODE:
        {
            DBTKEY      key ;
@@ -1325,6 +1367,7 @@ push(db, ...)
            DBT         value ;
            DB *        Db = db->dbp ;
            int         i ;
+           STRLEN      n_a;
 
            DBT_flags(key) ; 
            DBT_flags(value) ; 
@@ -1340,8 +1383,8 @@ push(db, ...)
                {
                    
                    ++ (* (int*)key.data) ;
-                   value.data = SvPV(ST(i), na) ;
-                   value.size = na ;
+                   value.data = SvPV(ST(i), n_a) ;
+                   value.size = n_a ;
                    RETVAL = (Db->put)(Db, NULL, &key, &value, 0) ;
                    if (RETVAL != 0)
                        break;
@@ -1349,8 +1392,8 @@ push(db, ...)
 #else
                for (i = items - 1 ; i > 0 ; --i)
                {
-                   value.data = SvPV(ST(i), na) ;
-                   value.size = na ;
+                   value.data = SvPV(ST(i), n_a) ;
+                   value.size = n_a ;
                    RETVAL = (Db->put)(Db, keyptr, &value, R_IAFTER) ;
                    if (RETVAL != 0)
                        break;
@@ -1365,6 +1408,7 @@ push(db, ...)
 I32
 length(db)
        DB_File         db
+       ALIAS:          FETCHSIZE = 1
        CODE:
            CurrentDB = db ;
            RETVAL = GetArrayLength(db) ;
@@ -1431,7 +1475,7 @@ db_put(db, key, value, flags=0)
 #endif
        OUTPUT:
          RETVAL
-         key           if (flags & (R_IAFTER|R_IBEFORE)) OutputKey(ST(1), key);
+         key           if (flagSet(flags, R_IAFTER) || flagSet(flags, R_IBEFORE)) OutputKey(ST(1), key);
 
 int
 db_fd(db)