More -Wall silencing from Michael Schwern and Jarkko Hietaniemi.
[p5sagit/p5-mst-13.2.git] / ext / DB_File / DB_File.xs
1 /* 
2
3  DB_File.xs -- Perl 5 interface to Berkeley DB 
4
5  written by Paul Marquess <Paul.Marquess@btinternet.com>
6  last modified 26th April 2001
7  version 1.77
8
9  All comments/suggestions/problems are welcome
10
11      Copyright (c) 1995-2001 Paul Marquess. All rights reserved.
12      This program is free software; you can redistribute it and/or
13      modify it under the same terms as Perl itself.
14
15  Changes:
16         0.1 -   Initial Release
17         0.2 -   No longer bombs out if dbopen returns an error.
18         0.3 -   Added some support for multiple btree compares
19         1.0 -   Complete support for multiple callbacks added.
20                 Fixed a problem with pushing a value onto an empty list.
21         1.01 -  Fixed a SunOS core dump problem.
22                 The return value from TIEHASH wasn't set to NULL when
23                 dbopen returned an error.
24         1.02 -  Use ALIAS to define TIEARRAY.
25                 Removed some redundant commented code.
26                 Merged OS2 code into the main distribution.
27                 Allow negative subscripts with RECNO interface.
28                 Changed the default flags to O_CREAT|O_RDWR
29         1.03 -  Added EXISTS
30         1.04 -  fixed a couple of bugs in hash_cb. Patches supplied by
31                 Dave Hammen, hammen@gothamcity.jsc.nasa.gov
32         1.05 -  Added logic to allow prefix & hash types to be specified via
33                 Makefile.PL
34         1.06 -  Minor namespace cleanup: Localized PrintBtree.
35         1.07 -  Fixed bug with RECNO, where bval wasn't defaulting to "\n". 
36         1.08 -  No change to DB_File.xs
37         1.09 -  Default mode for dbopen changed to 0666
38         1.10 -  Fixed fd method so that it still returns -1 for
39                 in-memory files when db 1.86 is used.
40         1.11 -  No change to DB_File.xs
41         1.12 -  No change to DB_File.xs
42         1.13 -  Tidied up a few casts.     
43         1.14 -  Made it illegal to tie an associative array to a RECNO
44                 database and an ordinary array to a HASH or BTREE database.
45         1.50 -  Make work with both DB 1.x or DB 2.x
46         1.51 -  Fixed a bug in mapping 1.x O_RDONLY flag to 2.x DB_RDONLY equivalent
47         1.52 -  Patch from Gisle Aas <gisle@aas.no> to suppress "use of 
48                 undefined value" warning with db_get and db_seq.
49         1.53 -  Added DB_RENUMBER to flags for recno.
50         1.54 -  Fixed bug in the fd method
51         1.55 -  Fix for AIX from Jarkko Hietaniemi
52         1.56 -  No change to DB_File.xs
53         1.57 -  added the #undef op to allow building with Threads support.
54         1.58 -  Fixed a problem with the use of sv_setpvn. When the
55                 size is specified as 0, it does a strlen on the data.
56                 This was ok for DB 1.x, but isn't for DB 2.x.
57         1.59 -  No change to DB_File.xs
58         1.60 -  Some code tidy up
59         1.61 -  added flagSet macro for DB 2.5.x
60                 fixed typo in O_RDONLY test.
61         1.62 -  No change to DB_File.xs
62         1.63 -  Fix to alllow DB 2.6.x to build.
63         1.64 -  Tidied up the 1.x to 2.x flags mapping code.
64                 Added a patch from Mark Kettenis <kettenis@wins.uva.nl>
65                 to fix a flag mapping problem with O_RDONLY on the Hurd
66         1.65 -  Fixed a bug in the PUSH logic.
67                 Added BOOT check that using 2.3.4 or greater
68         1.66 -  Added DBM filter code
69         1.67 -  Backed off the use of newSVpvn.
70                 Fixed DBM Filter code for Perl 5.004.
71                 Fixed a small memory leak in the filter code.
72         1.68 -  fixed backward compatability bug with R_IAFTER & R_IBEFORE
73                 merged in the 5.005_58 changes
74         1.69 -  fixed a bug in push -- DB_APPEND wasn't working properly.
75                 Fixed the R_SETCURSOR bug introduced in 1.68
76                 Added a new Perl variable $DB_File::db_ver 
77         1.70 -  Initialise $DB_File::db_ver and $DB_File::db_version with 
78                 GV_ADD|GV_ADDMULT -- bug spotted by Nick Ing-Simmons.
79                 Added a BOOT check to test for equivalent versions of db.h &
80                 libdb.a/so.
81         1.71 -  Support for Berkeley DB version 3.
82                 Support for Berkeley DB 2/3's backward compatability mode.
83                 Rewrote push
84         1.72 -  No change to DB_File.xs
85         1.73 -  No change to DB_File.xs
86         1.74 -  A call to open needed parenthesised to stop it clashing
87                 with a win32 macro.
88                 Added Perl core patches 7703 & 7801.
89         1.75 -  Fixed Perl core patch 7703.
90                 Added suppport to allow DB_File to be built with 
91                 Berkeley DB 3.2 -- btree_compare, btree_prefix and hash_cb
92                 needed to be changed.
93         1.76 -  No change to DB_File.xs
94         1.77 -  Tidied up a few types used in calling newSVpvn.
95
96 */
97
98 #include "EXTERN.h"  
99 #include "perl.h"
100 #include "XSUB.h"
101
102 #ifndef PERL_VERSION
103 #    include "patchlevel.h"
104 #    define PERL_REVISION       5
105 #    define PERL_VERSION        PATCHLEVEL
106 #    define PERL_SUBVERSION     SUBVERSION
107 #endif
108
109 #if PERL_REVISION == 5 && (PERL_VERSION < 4 || (PERL_VERSION == 4 && PERL_SUBVERSION <= 75 ))
110
111 #    define PL_sv_undef         sv_undef
112 #    define PL_na               na
113
114 #endif
115
116 /* DEFSV appears first in 5.004_56 */
117 #ifndef DEFSV
118 #    define DEFSV               GvSV(defgv)
119 #endif
120
121 /* Being the Berkeley DB we prefer the <sys/cdefs.h> (which will be
122  * shortly #included by the <db.h>) __attribute__ to the possibly
123  * already defined __attribute__, for example by GNUC or by Perl. */
124
125 #undef __attribute__
126
127 /* Since we dropped the gccish definition of __attribute__ we will want
128  * to redefine dNOOP, however (so that dTHX continues to work).  Yes,
129  * all this means that we can't do attribute checking on the DB_File,
130  * boo, hiss. */
131 #undef  dNOOP
132 #define dNOOP extern int Perl___notused
133
134 /* If Perl has been compiled with Threads support,the symbol op will
135    be defined here. This clashes with a field name in db.h, so get rid of it.
136  */
137 #ifdef op
138 #    undef op
139 #endif
140
141 #ifdef COMPAT185
142 #    include <db_185.h>
143 #else
144 #    include <db.h>
145 #endif
146
147 #ifdef CAN_PROTOTYPE
148 extern void __getBerkeleyDBInfo(void);
149 #endif
150
151 #ifndef pTHX
152 #    define pTHX
153 #    define pTHX_
154 #    define aTHX
155 #    define aTHX_
156 #endif
157
158 #ifndef newSVpvn
159 #    define newSVpvn(a,b)       newSVpv(a,b)
160 #endif
161
162 #include <fcntl.h> 
163
164 /* #define TRACE */
165 #define DBM_FILTERING
166
167 #ifdef TRACE
168 #    define Trace(x)        printf x
169 #else
170 #    define Trace(x)
171 #endif
172
173
174 #define DBT_clear(x)    Zero(&x, 1, DBT) ;
175
176 #ifdef DB_VERSION_MAJOR
177
178 #if DB_VERSION_MAJOR == 2
179 #    define BERKELEY_DB_1_OR_2
180 #endif
181
182 #if DB_VERSION_MAJOR > 3 || (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR >= 2)
183 #    define AT_LEAST_DB_3_2
184 #endif
185
186 /* map version 2 features & constants onto their version 1 equivalent */
187
188 #ifdef DB_Prefix_t
189 #    undef DB_Prefix_t
190 #endif
191 #define DB_Prefix_t     size_t
192
193 #ifdef DB_Hash_t
194 #    undef DB_Hash_t
195 #endif
196 #define DB_Hash_t       u_int32_t
197
198 /* DBTYPE stays the same */
199 /* HASHINFO, RECNOINFO and BTREEINFO  map to DB_INFO */
200 #if DB_VERSION_MAJOR == 2
201     typedef DB_INFO     INFO ;
202 #else /* DB_VERSION_MAJOR > 2 */
203 #    define DB_FIXEDLEN (0x8000)
204 #endif /* DB_VERSION_MAJOR == 2 */
205
206 /* version 2 has db_recno_t in place of recno_t */
207 typedef db_recno_t      recno_t;
208
209
210 #define R_CURSOR        DB_SET_RANGE
211 #define R_FIRST         DB_FIRST
212 #define R_IAFTER        DB_AFTER
213 #define R_IBEFORE       DB_BEFORE
214 #define R_LAST          DB_LAST
215 #define R_NEXT          DB_NEXT
216 #define R_NOOVERWRITE   DB_NOOVERWRITE
217 #define R_PREV          DB_PREV
218
219 #if DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR < 5
220 #  define R_SETCURSOR   0x800000
221 #else
222 #  define R_SETCURSOR   (-100)
223 #endif
224
225 #define R_RECNOSYNC     0
226 #define R_FIXEDLEN      DB_FIXEDLEN
227 #define R_DUP           DB_DUP
228
229
230 #define db_HA_hash      h_hash
231 #define db_HA_ffactor   h_ffactor
232 #define db_HA_nelem     h_nelem
233 #define db_HA_bsize     db_pagesize
234 #define db_HA_cachesize db_cachesize
235 #define db_HA_lorder    db_lorder
236
237 #define db_BT_compare   bt_compare
238 #define db_BT_prefix    bt_prefix
239 #define db_BT_flags     flags
240 #define db_BT_psize     db_pagesize
241 #define db_BT_cachesize db_cachesize
242 #define db_BT_lorder    db_lorder
243 #define db_BT_maxkeypage
244 #define db_BT_minkeypage
245
246
247 #define db_RE_reclen    re_len
248 #define db_RE_flags     flags
249 #define db_RE_bval      re_pad
250 #define db_RE_bfname    re_source
251 #define db_RE_psize     db_pagesize
252 #define db_RE_cachesize db_cachesize
253 #define db_RE_lorder    db_lorder
254
255 #define TXN     NULL,
256
257 #define do_SEQ(db, key, value, flag)    (db->cursor->c_get)(db->cursor, &key, &value, flag)
258
259
260 #define DBT_flags(x)    x.flags = 0
261 #define DB_flags(x, v)  x |= v 
262
263 #if DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR < 5
264 #    define flagSet(flags, bitmask)     ((flags) & (bitmask))
265 #else
266 #    define flagSet(flags, bitmask)     (((flags) & DB_OPFLAGS_MASK) == (bitmask))
267 #endif
268
269 #else /* db version 1.x */
270
271 #define BERKELEY_DB_1
272 #define BERKELEY_DB_1_OR_2
273
274 typedef union INFO {
275         HASHINFO        hash ;
276         RECNOINFO       recno ;
277         BTREEINFO       btree ;
278       } INFO ;
279
280
281 #ifdef mDB_Prefix_t 
282 #  ifdef DB_Prefix_t
283 #    undef DB_Prefix_t
284 #  endif
285 #  define DB_Prefix_t   mDB_Prefix_t 
286 #endif
287
288 #ifdef mDB_Hash_t
289 #  ifdef DB_Hash_t
290 #    undef DB_Hash_t
291 #  endif
292 #  define DB_Hash_t     mDB_Hash_t
293 #endif
294
295 #define db_HA_hash      hash.hash
296 #define db_HA_ffactor   hash.ffactor
297 #define db_HA_nelem     hash.nelem
298 #define db_HA_bsize     hash.bsize
299 #define db_HA_cachesize hash.cachesize
300 #define db_HA_lorder    hash.lorder
301
302 #define db_BT_compare   btree.compare
303 #define db_BT_prefix    btree.prefix
304 #define db_BT_flags     btree.flags
305 #define db_BT_psize     btree.psize
306 #define db_BT_cachesize btree.cachesize
307 #define db_BT_lorder    btree.lorder
308 #define db_BT_maxkeypage btree.maxkeypage
309 #define db_BT_minkeypage btree.minkeypage
310
311 #define db_RE_reclen    recno.reclen
312 #define db_RE_flags     recno.flags
313 #define db_RE_bval      recno.bval
314 #define db_RE_bfname    recno.bfname
315 #define db_RE_psize     recno.psize
316 #define db_RE_cachesize recno.cachesize
317 #define db_RE_lorder    recno.lorder
318
319 #define TXN     
320
321 #define do_SEQ(db, key, value, flag)    (db->dbp->seq)(db->dbp, &key, &value, flag)
322 #define DBT_flags(x)    
323 #define DB_flags(x, v)  
324 #define flagSet(flags, bitmask)        ((flags) & (bitmask))
325
326 #endif /* db version 1 */
327
328
329
330 #define db_DELETE(db, key, flags)       ((db->dbp)->del)(db->dbp, TXN &key, flags)
331 #define db_STORE(db, key, value, flags) ((db->dbp)->put)(db->dbp, TXN &key, &value, flags)
332 #define db_FETCH(db, key, flags)        ((db->dbp)->get)(db->dbp, TXN &key, &value, flags)
333
334 #define db_sync(db, flags)              ((db->dbp)->sync)(db->dbp, flags)
335 #define db_get(db, key, value, flags)   ((db->dbp)->get)(db->dbp, TXN &key, &value, flags)
336
337 #ifdef DB_VERSION_MAJOR
338 #define db_DESTROY(db)                  ( db->cursor->c_close(db->cursor),\
339                                           (db->dbp->close)(db->dbp, 0) )
340 #define db_close(db)                    ((db->dbp)->close)(db->dbp, 0)
341 #define db_del(db, key, flags)          (flagSet(flags, R_CURSOR)                                       \
342                                                 ? ((db->cursor)->c_del)(db->cursor, 0)          \
343                                                 : ((db->dbp)->del)(db->dbp, NULL, &key, flags) )
344
345 #else /* ! DB_VERSION_MAJOR */
346
347 #define db_DESTROY(db)                  ((db->dbp)->close)(db->dbp)
348 #define db_close(db)                    ((db->dbp)->close)(db->dbp)
349 #define db_del(db, key, flags)          ((db->dbp)->del)(db->dbp, &key, flags)
350 #define db_put(db, key, value, flags)   ((db->dbp)->put)(db->dbp, &key, &value, flags)
351
352 #endif /* ! DB_VERSION_MAJOR */
353
354
355 #define db_seq(db, key, value, flags)   do_SEQ(db, key, value, flags)
356
357 typedef struct {
358         DBTYPE  type ;
359         DB *    dbp ;
360         SV *    compare ;
361         SV *    prefix ;
362         SV *    hash ;
363         int     in_memory ;
364 #ifdef BERKELEY_DB_1_OR_2
365         INFO    info ;
366 #endif  
367 #ifdef DB_VERSION_MAJOR
368         DBC *   cursor ;
369 #endif
370 #ifdef DBM_FILTERING
371         SV *    filter_fetch_key ;
372         SV *    filter_store_key ;
373         SV *    filter_fetch_value ;
374         SV *    filter_store_value ;
375         int     filtering ;
376 #endif /* DBM_FILTERING */
377
378         } DB_File_type;
379
380 typedef DB_File_type * DB_File ;
381 typedef DBT DBTKEY ;
382
383 #ifdef DBM_FILTERING
384
385 #define ckFilter(arg,type,name)                                 \
386         if (db->type) {                                         \
387             SV * save_defsv ;                                   \
388             /* printf("filtering %s\n", name) ;*/               \
389             if (db->filtering)                                  \
390                 croak("recursion detected in %s", name) ;       \
391             db->filtering = TRUE ;                              \
392             save_defsv = newSVsv(DEFSV) ;                       \
393             sv_setsv(DEFSV, arg) ;                              \
394             PUSHMARK(sp) ;                                      \
395             (void) perl_call_sv(db->type, G_DISCARD|G_NOARGS);  \
396             sv_setsv(arg, DEFSV) ;                              \
397             sv_setsv(DEFSV, save_defsv) ;                       \
398             SvREFCNT_dec(save_defsv) ;                          \
399             db->filtering = FALSE ;                             \
400             /*printf("end of filtering %s\n", name) ;*/         \
401         }
402
403 #else
404
405 #define ckFilter(arg,type, name)
406
407 #endif /* DBM_FILTERING */
408
409 #define my_sv_setpvn(sv, d, s) sv_setpvn(sv, (s ? d : (void*)""), s)
410
411 #define OutputValue(arg, name)                                          \
412         { if (RETVAL == 0) {                                            \
413               my_sv_setpvn(arg, name.data, name.size) ;                 \
414               ckFilter(arg, filter_fetch_value,"filter_fetch_value") ;  \
415           }                                                             \
416         }
417
418 #define OutputKey(arg, name)                                            \
419         { if (RETVAL == 0)                                              \
420           {                                                             \
421                 if (db->type != DB_RECNO) {                             \
422                     my_sv_setpvn(arg, name.data, name.size);            \
423                 }                                                       \
424                 else                                                    \
425                     sv_setiv(arg, (I32)*(I32*)name.data - 1);           \
426               ckFilter(arg, filter_fetch_key,"filter_fetch_key") ;      \
427           }                                                             \
428         }
429
430
431 /* Internal Global Data */
432 static recno_t Value ; 
433 static recno_t zero = 0 ;
434 static DB_File CurrentDB ;
435 static DBTKEY empty ;
436
437 #ifdef DB_VERSION_MAJOR
438
439 static int
440 #ifdef CAN_PROTOTYPE
441 db_put(DB_File db, DBTKEY key, DBT value, u_int flags)
442 #else
443 db_put(db, key, value, flags)
444 DB_File         db ;
445 DBTKEY          key ;
446 DBT             value ;
447 u_int           flags ;
448 #endif
449 {
450     int status ;
451
452     if (flagSet(flags, R_IAFTER) || flagSet(flags, R_IBEFORE)) {
453         DBC * temp_cursor ;
454         DBT l_key, l_value;
455         
456 #if DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR < 6
457         if (((db->dbp)->cursor)(db->dbp, NULL, &temp_cursor) != 0)
458 #else
459         if (((db->dbp)->cursor)(db->dbp, NULL, &temp_cursor, 0) != 0)
460 #endif
461             return (-1) ;
462
463         memset(&l_key, 0, sizeof(l_key));
464         l_key.data = key.data;
465         l_key.size = key.size;
466         memset(&l_value, 0, sizeof(l_value));
467         l_value.data = value.data;
468         l_value.size = value.size;
469
470         if ( temp_cursor->c_get(temp_cursor, &l_key, &l_value, DB_SET) != 0) {
471             (void)temp_cursor->c_close(temp_cursor);
472             return (-1);
473         }
474
475         status = temp_cursor->c_put(temp_cursor, &key, &value, flags);
476         (void)temp_cursor->c_close(temp_cursor);
477             
478         return (status) ;
479     }   
480     
481     
482     if (flagSet(flags, R_CURSOR)) {
483         return ((db->cursor)->c_put)(db->cursor, &key, &value, DB_CURRENT);
484     }
485
486     if (flagSet(flags, R_SETCURSOR)) {
487         if ((db->dbp)->put(db->dbp, NULL, &key, &value, 0) != 0)
488                 return -1 ;
489         return ((db->cursor)->c_get)(db->cursor, &key, &value, DB_SET_RANGE);
490     
491     }
492
493     return ((db->dbp)->put)(db->dbp, NULL, &key, &value, flags) ;
494
495 }
496
497 #endif /* DB_VERSION_MAJOR */
498
499
500 static int
501 #ifdef AT_LEAST_DB_3_2
502
503 #ifdef CAN_PROTOTYPE
504 btree_compare(DB * db, const DBT *key1, const DBT *key2)
505 #else
506 btree_compare(db, key1, key2)
507 DB * db ;
508 const DBT * key1 ;
509 const DBT * key2 ;
510 #endif /* CAN_PROTOTYPE */
511
512 #else /* Berkeley DB < 3.2 */
513
514 #ifdef CAN_PROTOTYPE
515 btree_compare(const DBT *key1, const DBT *key2)
516 #else
517 btree_compare(key1, key2)
518 const DBT * key1 ;
519 const DBT * key2 ;
520 #endif
521
522 #endif
523
524 {
525 #ifdef dTHX
526     dTHX;
527 #endif    
528     dSP ;
529     char * data1, * data2 ;
530     int retval ;
531     int count ;
532     
533     data1 = (char *) key1->data ;
534     data2 = (char *) key2->data ;
535
536 #ifndef newSVpvn
537     /* As newSVpv will assume that the data pointer is a null terminated C 
538        string if the size parameter is 0, make sure that data points to an 
539        empty string if the length is 0
540     */
541     if (key1->size == 0)
542         data1 = "" ; 
543     if (key2->size == 0)
544         data2 = "" ;
545 #endif  
546
547     ENTER ;
548     SAVETMPS;
549
550     PUSHMARK(SP) ;
551     EXTEND(SP,2) ;
552     PUSHs(sv_2mortal(newSVpvn(data1,key1->size)));
553     PUSHs(sv_2mortal(newSVpvn(data2,key2->size)));
554     PUTBACK ;
555
556     count = perl_call_sv(CurrentDB->compare, G_SCALAR); 
557
558     SPAGAIN ;
559
560     if (count != 1)
561         croak ("DB_File btree_compare: expected 1 return value from compare sub, got %d\n", count) ;
562
563     retval = POPi ;
564
565     PUTBACK ;
566     FREETMPS ;
567     LEAVE ;
568     return (retval) ;
569
570 }
571
572 static DB_Prefix_t
573 #ifdef AT_LEAST_DB_3_2
574
575 #ifdef CAN_PROTOTYPE
576 btree_prefix(DB * db, const DBT *key1, const DBT *key2)
577 #else
578 btree_prefix(db, key1, key2)
579 Db * db ;
580 const DBT * key1 ;
581 const DBT * key2 ;
582 #endif
583
584 #else /* Berkeley DB < 3.2 */
585
586 #ifdef CAN_PROTOTYPE
587 btree_prefix(const DBT *key1, const DBT *key2)
588 #else
589 btree_prefix(key1, key2)
590 const DBT * key1 ;
591 const DBT * key2 ;
592 #endif
593
594 #endif
595 {
596 #ifdef dTHX
597     dTHX;
598 #endif    
599     dSP ;
600     char * data1, * data2 ;
601     int retval ;
602     int count ;
603     
604     data1 = (char *) key1->data ;
605     data2 = (char *) key2->data ;
606
607 #ifndef newSVpvn
608     /* As newSVpv will assume that the data pointer is a null terminated C 
609        string if the size parameter is 0, make sure that data points to an 
610        empty string if the length is 0
611     */
612     if (key1->size == 0)
613         data1 = "" ;
614     if (key2->size == 0)
615         data2 = "" ;
616 #endif  
617
618     ENTER ;
619     SAVETMPS;
620
621     PUSHMARK(SP) ;
622     EXTEND(SP,2) ;
623     PUSHs(sv_2mortal(newSVpvn(data1,key1->size)));
624     PUSHs(sv_2mortal(newSVpvn(data2,key2->size)));
625     PUTBACK ;
626
627     count = perl_call_sv(CurrentDB->prefix, G_SCALAR); 
628
629     SPAGAIN ;
630
631     if (count != 1)
632         croak ("DB_File btree_prefix: expected 1 return value from prefix sub, got %d\n", count) ;
633  
634     retval = POPi ;
635  
636     PUTBACK ;
637     FREETMPS ;
638     LEAVE ;
639
640     return (retval) ;
641 }
642
643
644 #ifdef BERKELEY_DB_1
645 #    define HASH_CB_SIZE_TYPE size_t
646 #else
647 #    define HASH_CB_SIZE_TYPE u_int32_t
648 #endif
649
650 static DB_Hash_t
651 #ifdef AT_LEAST_DB_3_2
652
653 #ifdef CAN_PROTOTYPE
654 hash_cb(DB * db, const void *data, u_int32_t size)
655 #else
656 hash_cb(db, data, size)
657 DB * db ;
658 const void * data ;
659 HASH_CB_SIZE_TYPE size ;
660 #endif
661
662 #else /* Berkeley DB < 3.2 */
663
664 #ifdef CAN_PROTOTYPE
665 hash_cb(const void *data, HASH_CB_SIZE_TYPE size)
666 #else
667 hash_cb(data, size)
668 const void * data ;
669 HASH_CB_SIZE_TYPE size ;
670 #endif
671
672 #endif
673 {
674 #ifdef dTHX
675     dTHX;
676 #endif    
677     dSP ;
678     int retval ;
679     int count ;
680
681 #ifndef newSVpvn
682     if (size == 0)
683         data = "" ;
684 #endif  
685
686      /* DGH - Next two lines added to fix corrupted stack problem */
687     ENTER ;
688     SAVETMPS;
689
690     PUSHMARK(SP) ;
691
692     XPUSHs(sv_2mortal(newSVpvn((char*)data,size)));
693     PUTBACK ;
694
695     count = perl_call_sv(CurrentDB->hash, G_SCALAR); 
696
697     SPAGAIN ;
698
699     if (count != 1)
700         croak ("DB_File hash_cb: expected 1 return value from hash sub, got %d\n", count) ;
701
702     retval = POPi ;
703
704     PUTBACK ;
705     FREETMPS ;
706     LEAVE ;
707
708     return (retval) ;
709 }
710
711
712 #if defined(TRACE) && defined(BERKELEY_DB_1_OR_2)
713
714 static void
715 #ifdef CAN_PROTOTYPE
716 PrintHash(INFO *hash)
717 #else
718 PrintHash(hash)
719 INFO * hash ;
720 #endif
721 {
722     printf ("HASH Info\n") ;
723     printf ("  hash      = %s\n", 
724                 (hash->db_HA_hash != NULL ? "redefined" : "default")) ;
725     printf ("  bsize     = %d\n", hash->db_HA_bsize) ;
726     printf ("  ffactor   = %d\n", hash->db_HA_ffactor) ;
727     printf ("  nelem     = %d\n", hash->db_HA_nelem) ;
728     printf ("  cachesize = %d\n", hash->db_HA_cachesize) ;
729     printf ("  lorder    = %d\n", hash->db_HA_lorder) ;
730
731 }
732
733 static void
734 #ifdef CAN_PROTOTYPE
735 PrintRecno(INFO *recno)
736 #else
737 PrintRecno(recno)
738 INFO * recno ;
739 #endif
740 {
741     printf ("RECNO Info\n") ;
742     printf ("  flags     = %d\n", recno->db_RE_flags) ;
743     printf ("  cachesize = %d\n", recno->db_RE_cachesize) ;
744     printf ("  psize     = %d\n", recno->db_RE_psize) ;
745     printf ("  lorder    = %d\n", recno->db_RE_lorder) ;
746     printf ("  reclen    = %ul\n", (unsigned long)recno->db_RE_reclen) ;
747     printf ("  bval      = %d 0x%x\n", recno->db_RE_bval, recno->db_RE_bval) ;
748     printf ("  bfname    = %d [%s]\n", recno->db_RE_bfname, recno->db_RE_bfname) ;
749 }
750
751 static void
752 #ifdef CAN_PROTOTYPE
753 PrintBtree(INFO *btree)
754 #else
755 PrintBtree(btree)
756 INFO * btree ;
757 #endif
758 {
759     printf ("BTREE Info\n") ;
760     printf ("  compare    = %s\n", 
761                 (btree->db_BT_compare ? "redefined" : "default")) ;
762     printf ("  prefix     = %s\n", 
763                 (btree->db_BT_prefix ? "redefined" : "default")) ;
764     printf ("  flags      = %d\n", btree->db_BT_flags) ;
765     printf ("  cachesize  = %d\n", btree->db_BT_cachesize) ;
766     printf ("  psize      = %d\n", btree->db_BT_psize) ;
767 #ifndef DB_VERSION_MAJOR
768     printf ("  maxkeypage = %d\n", btree->db_BT_maxkeypage) ;
769     printf ("  minkeypage = %d\n", btree->db_BT_minkeypage) ;
770 #endif
771     printf ("  lorder     = %d\n", btree->db_BT_lorder) ;
772 }
773
774 #else
775
776 #define PrintRecno(recno)
777 #define PrintHash(hash)
778 #define PrintBtree(btree)
779
780 #endif /* TRACE */
781
782
783 static I32
784 #ifdef CAN_PROTOTYPE
785 GetArrayLength(pTHX_ DB_File db)
786 #else
787 GetArrayLength(db)
788 DB_File db ;
789 #endif
790 {
791     DBT         key ;
792     DBT         value ;
793     int         RETVAL ;
794
795     DBT_clear(key) ;
796     DBT_clear(value) ;
797     RETVAL = do_SEQ(db, key, value, R_LAST) ;
798     if (RETVAL == 0)
799         RETVAL = *(I32 *)key.data ;
800     else /* No key means empty file */
801         RETVAL = 0 ;
802
803     return ((I32)RETVAL) ;
804 }
805
806 static recno_t
807 #ifdef CAN_PROTOTYPE
808 GetRecnoKey(pTHX_ DB_File db, I32 value)
809 #else
810 GetRecnoKey(db, value)
811 DB_File  db ;
812 I32      value ;
813 #endif
814 {
815     if (value < 0) {
816         /* Get the length of the array */
817         I32 length = GetArrayLength(aTHX_ db) ;
818
819         /* check for attempt to write before start of array */
820         if (length + value + 1 <= 0)
821             croak("Modification of non-creatable array value attempted, subscript %ld", (long)value) ;
822
823         value = length + value + 1 ;
824     }
825     else
826         ++ value ;
827
828     return value ;
829 }
830
831
832 static DB_File
833 #ifdef CAN_PROTOTYPE
834 ParseOpenInfo(pTHX_ int isHASH, char *name, int flags, int mode, SV *sv)
835 #else
836 ParseOpenInfo(isHASH, name, flags, mode, sv)
837 int    isHASH ;
838 char * name ;
839 int    flags ;
840 int    mode ;
841 SV *   sv ;
842 #endif
843 {
844
845 #ifdef BERKELEY_DB_1_OR_2 /* Berkeley DB Version 1  or 2 */
846
847     SV **       svp;
848     HV *        action ;
849     DB_File     RETVAL = (DB_File)safemalloc(sizeof(DB_File_type)) ;
850     void *      openinfo = NULL ;
851     INFO        * info  = &RETVAL->info ;
852     STRLEN      n_a;
853
854 /* printf("In ParseOpenInfo name=[%s] flags=[%d] mode = [%d]\n", name, flags, mode) ;  */
855     Zero(RETVAL, 1, DB_File_type) ;
856
857     /* Default to HASH */
858 #ifdef DBM_FILTERING
859     RETVAL->filtering = 0 ;
860     RETVAL->filter_fetch_key = RETVAL->filter_store_key = 
861     RETVAL->filter_fetch_value = RETVAL->filter_store_value =
862 #endif /* DBM_FILTERING */
863     RETVAL->hash = RETVAL->compare = RETVAL->prefix = NULL ;
864     RETVAL->type = DB_HASH ;
865
866      /* DGH - Next line added to avoid SEGV on existing hash DB */
867     CurrentDB = RETVAL; 
868
869     /* fd for 1.86 hash in memory files doesn't return -1 like 1.85 */
870     RETVAL->in_memory = (name == NULL) ;
871
872     if (sv)
873     {
874         if (! SvROK(sv) )
875             croak ("type parameter is not a reference") ;
876
877         svp  = hv_fetch( (HV*)SvRV(sv), "GOT", 3, FALSE) ;
878         if (svp && SvOK(*svp))
879             action  = (HV*) SvRV(*svp) ;
880         else
881             croak("internal error") ;
882
883         if (sv_isa(sv, "DB_File::HASHINFO"))
884         {
885
886             if (!isHASH)
887                 croak("DB_File can only tie an associative array to a DB_HASH database") ;
888
889             RETVAL->type = DB_HASH ;
890             openinfo = (void*)info ;
891   
892             svp = hv_fetch(action, "hash", 4, FALSE); 
893
894             if (svp && SvOK(*svp))
895             {
896                 info->db_HA_hash = hash_cb ;
897                 RETVAL->hash = newSVsv(*svp) ;
898             }
899             else
900                 info->db_HA_hash = NULL ;
901
902            svp = hv_fetch(action, "ffactor", 7, FALSE);
903            info->db_HA_ffactor = svp ? SvIV(*svp) : 0;
904          
905            svp = hv_fetch(action, "nelem", 5, FALSE);
906            info->db_HA_nelem = svp ? SvIV(*svp) : 0;
907          
908            svp = hv_fetch(action, "bsize", 5, FALSE);
909            info->db_HA_bsize = svp ? SvIV(*svp) : 0;
910            
911            svp = hv_fetch(action, "cachesize", 9, FALSE);
912            info->db_HA_cachesize = svp ? SvIV(*svp) : 0;
913          
914            svp = hv_fetch(action, "lorder", 6, FALSE);
915            info->db_HA_lorder = svp ? SvIV(*svp) : 0;
916
917            PrintHash(info) ; 
918         }
919         else if (sv_isa(sv, "DB_File::BTREEINFO"))
920         {
921             if (!isHASH)
922                 croak("DB_File can only tie an associative array to a DB_BTREE database");
923
924             RETVAL->type = DB_BTREE ;
925             openinfo = (void*)info ;
926    
927             svp = hv_fetch(action, "compare", 7, FALSE);
928             if (svp && SvOK(*svp))
929             {
930                 info->db_BT_compare = btree_compare ;
931                 RETVAL->compare = newSVsv(*svp) ;
932             }
933             else
934                 info->db_BT_compare = NULL ;
935
936             svp = hv_fetch(action, "prefix", 6, FALSE);
937             if (svp && SvOK(*svp))
938             {
939                 info->db_BT_prefix = btree_prefix ;
940                 RETVAL->prefix = newSVsv(*svp) ;
941             }
942             else
943                 info->db_BT_prefix = NULL ;
944
945             svp = hv_fetch(action, "flags", 5, FALSE);
946             info->db_BT_flags = svp ? SvIV(*svp) : 0;
947    
948             svp = hv_fetch(action, "cachesize", 9, FALSE);
949             info->db_BT_cachesize = svp ? SvIV(*svp) : 0;
950          
951 #ifndef DB_VERSION_MAJOR
952             svp = hv_fetch(action, "minkeypage", 10, FALSE);
953             info->btree.minkeypage = svp ? SvIV(*svp) : 0;
954         
955             svp = hv_fetch(action, "maxkeypage", 10, FALSE);
956             info->btree.maxkeypage = svp ? SvIV(*svp) : 0;
957 #endif
958
959             svp = hv_fetch(action, "psize", 5, FALSE);
960             info->db_BT_psize = svp ? SvIV(*svp) : 0;
961          
962             svp = hv_fetch(action, "lorder", 6, FALSE);
963             info->db_BT_lorder = svp ? SvIV(*svp) : 0;
964
965             PrintBtree(info) ;
966          
967         }
968         else if (sv_isa(sv, "DB_File::RECNOINFO"))
969         {
970             if (isHASH)
971                 croak("DB_File can only tie an array to a DB_RECNO database");
972
973             RETVAL->type = DB_RECNO ;
974             openinfo = (void *)info ;
975
976             info->db_RE_flags = 0 ;
977
978             svp = hv_fetch(action, "flags", 5, FALSE);
979             info->db_RE_flags = (u_long) (svp ? SvIV(*svp) : 0);
980          
981             svp = hv_fetch(action, "reclen", 6, FALSE);
982             info->db_RE_reclen = (size_t) (svp ? SvIV(*svp) : 0);
983          
984             svp = hv_fetch(action, "cachesize", 9, FALSE);
985             info->db_RE_cachesize = (u_int) (svp ? SvIV(*svp) : 0);
986          
987             svp = hv_fetch(action, "psize", 5, FALSE);
988             info->db_RE_psize = (u_int) (svp ? SvIV(*svp) : 0);
989          
990             svp = hv_fetch(action, "lorder", 6, FALSE);
991             info->db_RE_lorder = (int) (svp ? SvIV(*svp) : 0);
992
993 #ifdef DB_VERSION_MAJOR
994             info->re_source = name ;
995             name = NULL ;
996 #endif
997             svp = hv_fetch(action, "bfname", 6, FALSE); 
998             if (svp && SvOK(*svp)) {
999                 char * ptr = SvPV(*svp,n_a) ;
1000 #ifdef DB_VERSION_MAJOR
1001                 name = (char*) n_a ? ptr : NULL ;
1002 #else
1003                 info->db_RE_bfname = (char*) (n_a ? ptr : NULL) ;
1004 #endif
1005             }
1006             else
1007 #ifdef DB_VERSION_MAJOR
1008                 name = NULL ;
1009 #else
1010                 info->db_RE_bfname = NULL ;
1011 #endif
1012          
1013             svp = hv_fetch(action, "bval", 4, FALSE);
1014 #ifdef DB_VERSION_MAJOR
1015             if (svp && SvOK(*svp))
1016             {
1017                 int value ;
1018                 if (SvPOK(*svp))
1019                     value = (int)*SvPV(*svp, n_a) ;
1020                 else
1021                     value = SvIV(*svp) ;
1022
1023                 if (info->flags & DB_FIXEDLEN) {
1024                     info->re_pad = value ;
1025                     info->flags |= DB_PAD ;
1026                 }
1027                 else {
1028                     info->re_delim = value ;
1029                     info->flags |= DB_DELIMITER ;
1030                 }
1031
1032             }
1033 #else
1034             if (svp && SvOK(*svp))
1035             {
1036                 if (SvPOK(*svp))
1037                     info->db_RE_bval = (u_char)*SvPV(*svp, n_a) ;
1038                 else
1039                     info->db_RE_bval = (u_char)(unsigned long) SvIV(*svp) ;
1040                 DB_flags(info->flags, DB_DELIMITER) ;
1041
1042             }
1043             else
1044             {
1045                 if (info->db_RE_flags & R_FIXEDLEN)
1046                     info->db_RE_bval = (u_char) ' ' ;
1047                 else
1048                     info->db_RE_bval = (u_char) '\n' ;
1049                 DB_flags(info->flags, DB_DELIMITER) ;
1050             }
1051 #endif
1052
1053 #ifdef DB_RENUMBER
1054             info->flags |= DB_RENUMBER ;
1055 #endif
1056          
1057             PrintRecno(info) ;
1058         }
1059         else
1060             croak("type is not of type DB_File::HASHINFO, DB_File::BTREEINFO or DB_File::RECNOINFO");
1061     }
1062
1063
1064     /* OS2 Specific Code */
1065 #ifdef OS2
1066 #ifdef __EMX__
1067     flags |= O_BINARY;
1068 #endif /* __EMX__ */
1069 #endif /* OS2 */
1070
1071 #ifdef DB_VERSION_MAJOR
1072
1073     {
1074         int             Flags = 0 ;
1075         int             status ;
1076
1077         /* Map 1.x flags to 2.x flags */
1078         if ((flags & O_CREAT) == O_CREAT)
1079             Flags |= DB_CREATE ;
1080
1081 #if O_RDONLY == 0
1082         if (flags == O_RDONLY)
1083 #else
1084         if ((flags & O_RDONLY) == O_RDONLY && (flags & O_RDWR) != O_RDWR)
1085 #endif
1086             Flags |= DB_RDONLY ;
1087
1088 #ifdef O_TRUNC
1089         if ((flags & O_TRUNC) == O_TRUNC)
1090             Flags |= DB_TRUNCATE ;
1091 #endif
1092
1093         status = db_open(name, RETVAL->type, Flags, mode, NULL, openinfo, &RETVAL->dbp) ; 
1094         if (status == 0)
1095 #if DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR < 6
1096             status = (RETVAL->dbp->cursor)(RETVAL->dbp, NULL, &RETVAL->cursor) ;
1097 #else
1098             status = (RETVAL->dbp->cursor)(RETVAL->dbp, NULL, &RETVAL->cursor,
1099                         0) ;
1100 #endif
1101
1102         if (status)
1103             RETVAL->dbp = NULL ;
1104
1105     }
1106 #else
1107
1108 #if defined(DB_LIBRARY_COMPATIBILITY_API) && DB_VERSION_MAJOR > 2
1109     RETVAL->dbp = __db185_open(name, flags, mode, RETVAL->type, openinfo) ; 
1110 #else    
1111     RETVAL->dbp = dbopen(name, flags, mode, RETVAL->type, openinfo) ; 
1112 #endif /* DB_LIBRARY_COMPATIBILITY_API */
1113
1114 #endif
1115
1116     return (RETVAL) ;
1117
1118 #else /* Berkeley DB Version > 2 */
1119
1120     SV **       svp;
1121     HV *        action ;
1122     DB_File     RETVAL = (DB_File)safemalloc(sizeof(DB_File_type)) ;
1123     DB *        dbp ;
1124     STRLEN      n_a;
1125     int         status ;
1126
1127 /* printf("In ParseOpenInfo name=[%s] flags=[%d] mode = [%d]\n", name, flags, mode) ;  */
1128     Zero(RETVAL, 1, DB_File_type) ;
1129
1130     /* Default to HASH */
1131 #ifdef DBM_FILTERING
1132     RETVAL->filtering = 0 ;
1133     RETVAL->filter_fetch_key = RETVAL->filter_store_key = 
1134     RETVAL->filter_fetch_value = RETVAL->filter_store_value =
1135 #endif /* DBM_FILTERING */
1136     RETVAL->hash = RETVAL->compare = RETVAL->prefix = NULL ;
1137     RETVAL->type = DB_HASH ;
1138
1139      /* DGH - Next line added to avoid SEGV on existing hash DB */
1140     CurrentDB = RETVAL; 
1141
1142     /* fd for 1.86 hash in memory files doesn't return -1 like 1.85 */
1143     RETVAL->in_memory = (name == NULL) ;
1144
1145     status = db_create(&RETVAL->dbp, NULL,0) ;
1146     /* printf("db_create returned %d %s\n", status, db_strerror(status)) ; */
1147     if (status) {
1148         RETVAL->dbp = NULL ;
1149         return (RETVAL) ;
1150     }   
1151     dbp = RETVAL->dbp ;
1152
1153     if (sv)
1154     {
1155         if (! SvROK(sv) )
1156             croak ("type parameter is not a reference") ;
1157
1158         svp  = hv_fetch( (HV*)SvRV(sv), "GOT", 3, FALSE) ;
1159         if (svp && SvOK(*svp))
1160             action  = (HV*) SvRV(*svp) ;
1161         else
1162             croak("internal error") ;
1163
1164         if (sv_isa(sv, "DB_File::HASHINFO"))
1165         {
1166
1167             if (!isHASH)
1168                 croak("DB_File can only tie an associative array to a DB_HASH database") ;
1169
1170             RETVAL->type = DB_HASH ;
1171   
1172             svp = hv_fetch(action, "hash", 4, FALSE); 
1173
1174             if (svp && SvOK(*svp))
1175             {
1176                 (void)dbp->set_h_hash(dbp, hash_cb) ;
1177                 RETVAL->hash = newSVsv(*svp) ;
1178             }
1179
1180            svp = hv_fetch(action, "ffactor", 7, FALSE);
1181            if (svp)
1182                (void)dbp->set_h_ffactor(dbp, SvIV(*svp)) ;
1183          
1184            svp = hv_fetch(action, "nelem", 5, FALSE);
1185            if (svp)
1186                (void)dbp->set_h_nelem(dbp, SvIV(*svp)) ;
1187          
1188            svp = hv_fetch(action, "bsize", 5, FALSE);
1189            if (svp)
1190                (void)dbp->set_pagesize(dbp, SvIV(*svp));
1191            
1192            svp = hv_fetch(action, "cachesize", 9, FALSE);
1193            if (svp)
1194                (void)dbp->set_cachesize(dbp, 0, SvIV(*svp), 0) ;
1195          
1196            svp = hv_fetch(action, "lorder", 6, FALSE);
1197            if (svp)
1198                (void)dbp->set_lorder(dbp, SvIV(*svp)) ;
1199
1200            PrintHash(info) ; 
1201         }
1202         else if (sv_isa(sv, "DB_File::BTREEINFO"))
1203         {
1204             if (!isHASH)
1205                 croak("DB_File can only tie an associative array to a DB_BTREE database");
1206
1207             RETVAL->type = DB_BTREE ;
1208    
1209             svp = hv_fetch(action, "compare", 7, FALSE);
1210             if (svp && SvOK(*svp))
1211             {
1212                 (void)dbp->set_bt_compare(dbp, btree_compare) ;
1213                 RETVAL->compare = newSVsv(*svp) ;
1214             }
1215
1216             svp = hv_fetch(action, "prefix", 6, FALSE);
1217             if (svp && SvOK(*svp))
1218             {
1219                 (void)dbp->set_bt_prefix(dbp, btree_prefix) ;
1220                 RETVAL->prefix = newSVsv(*svp) ;
1221             }
1222
1223            svp = hv_fetch(action, "flags", 5, FALSE);
1224            if (svp)
1225                (void)dbp->set_flags(dbp, SvIV(*svp)) ;
1226    
1227            svp = hv_fetch(action, "cachesize", 9, FALSE);
1228            if (svp)
1229                (void)dbp->set_cachesize(dbp, 0, SvIV(*svp), 0) ;
1230          
1231            svp = hv_fetch(action, "psize", 5, FALSE);
1232            if (svp)
1233                (void)dbp->set_pagesize(dbp, SvIV(*svp)) ;
1234          
1235            svp = hv_fetch(action, "lorder", 6, FALSE);
1236            if (svp)
1237                (void)dbp->set_lorder(dbp, SvIV(*svp)) ;
1238
1239             PrintBtree(info) ;
1240          
1241         }
1242         else if (sv_isa(sv, "DB_File::RECNOINFO"))
1243         {
1244             int fixed = FALSE ;
1245
1246             if (isHASH)
1247                 croak("DB_File can only tie an array to a DB_RECNO database");
1248
1249             RETVAL->type = DB_RECNO ;
1250
1251            svp = hv_fetch(action, "flags", 5, FALSE);
1252            if (svp) {
1253                 int flags = SvIV(*svp) ;
1254                 /* remove FIXDLEN, if present */
1255                 if (flags & DB_FIXEDLEN) {
1256                     fixed = TRUE ;
1257                     flags &= ~DB_FIXEDLEN ;
1258                 }
1259            }
1260
1261            svp = hv_fetch(action, "cachesize", 9, FALSE);
1262            if (svp) {
1263                status = dbp->set_cachesize(dbp, 0, SvIV(*svp), 0) ;
1264            }
1265          
1266            svp = hv_fetch(action, "psize", 5, FALSE);
1267            if (svp) {
1268                status = dbp->set_pagesize(dbp, SvIV(*svp)) ;
1269             }
1270          
1271            svp = hv_fetch(action, "lorder", 6, FALSE);
1272            if (svp) {
1273                status = dbp->set_lorder(dbp, SvIV(*svp)) ;
1274            }
1275
1276             svp = hv_fetch(action, "bval", 4, FALSE);
1277             if (svp && SvOK(*svp))
1278             {
1279                 int value ;
1280                 if (SvPOK(*svp))
1281                     value = (int)*SvPV(*svp, n_a) ;
1282                 else
1283                     value = SvIV(*svp) ;
1284
1285                 if (fixed) {
1286                     status = dbp->set_re_pad(dbp, value) ;
1287                 }
1288                 else {
1289                     status = dbp->set_re_delim(dbp, value) ;
1290                 }
1291
1292             }
1293
1294            if (fixed) {
1295                svp = hv_fetch(action, "reclen", 6, FALSE);
1296                if (svp) {
1297                    u_int32_t len =  (u_int32_t)SvIV(*svp) ;
1298                    status = dbp->set_re_len(dbp, len) ;
1299                }    
1300            }
1301          
1302             if (name != NULL) {
1303                 status = dbp->set_re_source(dbp, name) ;
1304                 name = NULL ;
1305             }   
1306
1307             svp = hv_fetch(action, "bfname", 6, FALSE); 
1308             if (svp && SvOK(*svp)) {
1309                 char * ptr = SvPV(*svp,n_a) ;
1310                 name = (char*) n_a ? ptr : NULL ;
1311             }
1312             else
1313                 name = NULL ;
1314          
1315
1316             status = dbp->set_flags(dbp, DB_RENUMBER) ;
1317          
1318                 if (flags){
1319                     (void)dbp->set_flags(dbp, flags) ;
1320                 }
1321             PrintRecno(info) ;
1322         }
1323         else
1324             croak("type is not of type DB_File::HASHINFO, DB_File::BTREEINFO or DB_File::RECNOINFO");
1325     }
1326
1327     {
1328         int             Flags = 0 ;
1329         int             status ;
1330
1331         /* Map 1.x flags to 3.x flags */
1332         if ((flags & O_CREAT) == O_CREAT)
1333             Flags |= DB_CREATE ;
1334
1335 #if O_RDONLY == 0
1336         if (flags == O_RDONLY)
1337 #else
1338         if ((flags & O_RDONLY) == O_RDONLY && (flags & O_RDWR) != O_RDWR)
1339 #endif
1340             Flags |= DB_RDONLY ;
1341
1342 #ifdef O_TRUNC
1343         if ((flags & O_TRUNC) == O_TRUNC)
1344             Flags |= DB_TRUNCATE ;
1345 #endif
1346
1347         status = (RETVAL->dbp->open)(RETVAL->dbp, name, NULL, RETVAL->type, 
1348                                 Flags, mode) ; 
1349         /* printf("open returned %d %s\n", status, db_strerror(status)) ; */
1350
1351         if (status == 0)
1352             status = (RETVAL->dbp->cursor)(RETVAL->dbp, NULL, &RETVAL->cursor,
1353                         0) ;
1354         /* printf("cursor returned %d %s\n", status, db_strerror(status)) ; */
1355
1356         if (status)
1357             RETVAL->dbp = NULL ;
1358
1359     }
1360
1361     return (RETVAL) ;
1362
1363 #endif /* Berkeley DB Version > 2 */
1364
1365 } /* ParseOpenInfo */
1366
1367
1368 static double 
1369 #ifdef CAN_PROTOTYPE
1370 constant(char *name, int arg)
1371 #else
1372 constant(name, arg)
1373 char *name;
1374 int arg;
1375 #endif
1376 {
1377     errno = 0;
1378     switch (*name) {
1379     case 'A':
1380         break;
1381     case 'B':
1382         if (strEQ(name, "BTREEMAGIC"))
1383 #ifdef BTREEMAGIC
1384             return BTREEMAGIC;
1385 #else
1386             goto not_there;
1387 #endif
1388         if (strEQ(name, "BTREEVERSION"))
1389 #ifdef BTREEVERSION
1390             return BTREEVERSION;
1391 #else
1392             goto not_there;
1393 #endif
1394         break;
1395     case 'C':
1396         break;
1397     case 'D':
1398         if (strEQ(name, "DB_LOCK"))
1399 #ifdef DB_LOCK
1400             return DB_LOCK;
1401 #else
1402             goto not_there;
1403 #endif
1404         if (strEQ(name, "DB_SHMEM"))
1405 #ifdef DB_SHMEM
1406             return DB_SHMEM;
1407 #else
1408             goto not_there;
1409 #endif
1410         if (strEQ(name, "DB_TXN"))
1411 #ifdef DB_TXN
1412             return (U32)DB_TXN;
1413 #else
1414             goto not_there;
1415 #endif
1416         break;
1417     case 'E':
1418         break;
1419     case 'F':
1420         break;
1421     case 'G':
1422         break;
1423     case 'H':
1424         if (strEQ(name, "HASHMAGIC"))
1425 #ifdef HASHMAGIC
1426             return HASHMAGIC;
1427 #else
1428             goto not_there;
1429 #endif
1430         if (strEQ(name, "HASHVERSION"))
1431 #ifdef HASHVERSION
1432             return HASHVERSION;
1433 #else
1434             goto not_there;
1435 #endif
1436         break;
1437     case 'I':
1438         break;
1439     case 'J':
1440         break;
1441     case 'K':
1442         break;
1443     case 'L':
1444         break;
1445     case 'M':
1446         if (strEQ(name, "MAX_PAGE_NUMBER"))
1447 #ifdef MAX_PAGE_NUMBER
1448             return (U32)MAX_PAGE_NUMBER;
1449 #else
1450             goto not_there;
1451 #endif
1452         if (strEQ(name, "MAX_PAGE_OFFSET"))
1453 #ifdef MAX_PAGE_OFFSET
1454             return MAX_PAGE_OFFSET;
1455 #else
1456             goto not_there;
1457 #endif
1458         if (strEQ(name, "MAX_REC_NUMBER"))
1459 #ifdef MAX_REC_NUMBER
1460             return (U32)MAX_REC_NUMBER;
1461 #else
1462             goto not_there;
1463 #endif
1464         break;
1465     case 'N':
1466         break;
1467     case 'O':
1468         break;
1469     case 'P':
1470         break;
1471     case 'Q':
1472         break;
1473     case 'R':
1474         if (strEQ(name, "RET_ERROR"))
1475 #ifdef RET_ERROR
1476             return RET_ERROR;
1477 #else
1478             goto not_there;
1479 #endif
1480         if (strEQ(name, "RET_SPECIAL"))
1481 #ifdef RET_SPECIAL
1482             return RET_SPECIAL;
1483 #else
1484             goto not_there;
1485 #endif
1486         if (strEQ(name, "RET_SUCCESS"))
1487 #ifdef RET_SUCCESS
1488             return RET_SUCCESS;
1489 #else
1490             goto not_there;
1491 #endif
1492         if (strEQ(name, "R_CURSOR"))
1493 #ifdef R_CURSOR
1494             return R_CURSOR;
1495 #else
1496             goto not_there;
1497 #endif
1498         if (strEQ(name, "R_DUP"))
1499 #ifdef R_DUP
1500             return R_DUP;
1501 #else
1502             goto not_there;
1503 #endif
1504         if (strEQ(name, "R_FIRST"))
1505 #ifdef R_FIRST
1506             return R_FIRST;
1507 #else
1508             goto not_there;
1509 #endif
1510         if (strEQ(name, "R_FIXEDLEN"))
1511 #ifdef R_FIXEDLEN
1512             return R_FIXEDLEN;
1513 #else
1514             goto not_there;
1515 #endif
1516         if (strEQ(name, "R_IAFTER"))
1517 #ifdef R_IAFTER
1518             return R_IAFTER;
1519 #else
1520             goto not_there;
1521 #endif
1522         if (strEQ(name, "R_IBEFORE"))
1523 #ifdef R_IBEFORE
1524             return R_IBEFORE;
1525 #else
1526             goto not_there;
1527 #endif
1528         if (strEQ(name, "R_LAST"))
1529 #ifdef R_LAST
1530             return R_LAST;
1531 #else
1532             goto not_there;
1533 #endif
1534         if (strEQ(name, "R_NEXT"))
1535 #ifdef R_NEXT
1536             return R_NEXT;
1537 #else
1538             goto not_there;
1539 #endif
1540         if (strEQ(name, "R_NOKEY"))
1541 #ifdef R_NOKEY
1542             return R_NOKEY;
1543 #else
1544             goto not_there;
1545 #endif
1546         if (strEQ(name, "R_NOOVERWRITE"))
1547 #ifdef R_NOOVERWRITE
1548             return R_NOOVERWRITE;
1549 #else
1550             goto not_there;
1551 #endif
1552         if (strEQ(name, "R_PREV"))
1553 #ifdef R_PREV
1554             return R_PREV;
1555 #else
1556             goto not_there;
1557 #endif
1558         if (strEQ(name, "R_RECNOSYNC"))
1559 #ifdef R_RECNOSYNC
1560             return R_RECNOSYNC;
1561 #else
1562             goto not_there;
1563 #endif
1564         if (strEQ(name, "R_SETCURSOR"))
1565 #ifdef R_SETCURSOR
1566             return R_SETCURSOR;
1567 #else
1568             goto not_there;
1569 #endif
1570         if (strEQ(name, "R_SNAPSHOT"))
1571 #ifdef R_SNAPSHOT
1572             return R_SNAPSHOT;
1573 #else
1574             goto not_there;
1575 #endif
1576         break;
1577     case 'S':
1578         break;
1579     case 'T':
1580         break;
1581     case 'U':
1582         break;
1583     case 'V':
1584         break;
1585     case 'W':
1586         break;
1587     case 'X':
1588         break;
1589     case 'Y':
1590         break;
1591     case 'Z':
1592         break;
1593     case '_':
1594         break;
1595     }
1596     errno = EINVAL;
1597     return 0;
1598
1599 not_there:
1600     errno = ENOENT;
1601     return 0;
1602 }
1603
1604 MODULE = DB_File        PACKAGE = DB_File       PREFIX = db_
1605
1606 BOOT:
1607   {
1608     __getBerkeleyDBInfo() ;
1609  
1610     DBT_clear(empty) ; 
1611     empty.data = &zero ;
1612     empty.size =  sizeof(recno_t) ;
1613   }
1614
1615 double
1616 constant(name,arg)
1617         char *          name
1618         int             arg
1619
1620
1621 DB_File
1622 db_DoTie_(isHASH, dbtype, name=undef, flags=O_CREAT|O_RDWR, mode=0666, type=DB_HASH)
1623         int             isHASH
1624         char *          dbtype
1625         int             flags
1626         int             mode
1627         CODE:
1628         {
1629             char *      name = (char *) NULL ; 
1630             SV *        sv = (SV *) NULL ; 
1631             STRLEN      n_a;
1632
1633             if (items >= 3 && SvOK(ST(2))) 
1634                 name = (char*) SvPV(ST(2), n_a) ; 
1635
1636             if (items == 6)
1637                 sv = ST(5) ;
1638
1639             RETVAL = ParseOpenInfo(aTHX_ isHASH, name, flags, mode, sv) ;
1640             if (RETVAL->dbp == NULL)
1641                 RETVAL = NULL ;
1642         }
1643         OUTPUT: 
1644             RETVAL
1645
1646 int
1647 db_DESTROY(db)
1648         DB_File         db
1649         INIT:
1650           CurrentDB = db ;
1651         CLEANUP:
1652           if (db->hash)
1653             SvREFCNT_dec(db->hash) ;
1654           if (db->compare)
1655             SvREFCNT_dec(db->compare) ;
1656           if (db->prefix)
1657             SvREFCNT_dec(db->prefix) ;
1658 #ifdef DBM_FILTERING
1659           if (db->filter_fetch_key)
1660             SvREFCNT_dec(db->filter_fetch_key) ;
1661           if (db->filter_store_key)
1662             SvREFCNT_dec(db->filter_store_key) ;
1663           if (db->filter_fetch_value)
1664             SvREFCNT_dec(db->filter_fetch_value) ;
1665           if (db->filter_store_value)
1666             SvREFCNT_dec(db->filter_store_value) ;
1667 #endif /* DBM_FILTERING */
1668           safefree(db) ;
1669 #ifdef DB_VERSION_MAJOR
1670           if (RETVAL > 0)
1671             RETVAL = -1 ;
1672 #endif
1673
1674
1675 int
1676 db_DELETE(db, key, flags=0)
1677         DB_File         db
1678         DBTKEY          key
1679         u_int           flags
1680         INIT:
1681           CurrentDB = db ;
1682
1683
1684 int
1685 db_EXISTS(db, key)
1686         DB_File         db
1687         DBTKEY          key
1688         CODE:
1689         {
1690           DBT           value ;
1691         
1692           DBT_clear(value) ; 
1693           CurrentDB = db ;
1694           RETVAL = (((db->dbp)->get)(db->dbp, TXN &key, &value, 0) == 0) ;
1695         }
1696         OUTPUT:
1697           RETVAL
1698
1699 int
1700 db_FETCH(db, key, flags=0)
1701         DB_File         db
1702         DBTKEY          key
1703         u_int           flags
1704         CODE:
1705         {
1706             DBT         value ;
1707
1708             DBT_clear(value) ; 
1709             CurrentDB = db ;
1710             /* RETVAL = ((db->dbp)->get)(db->dbp, TXN &key, &value, flags) ; */
1711             RETVAL = db_get(db, key, value, flags) ;
1712             ST(0) = sv_newmortal();
1713             OutputValue(ST(0), value)
1714         }
1715
1716 int
1717 db_STORE(db, key, value, flags=0)
1718         DB_File         db
1719         DBTKEY          key
1720         DBT             value
1721         u_int           flags
1722         INIT:
1723           CurrentDB = db ;
1724
1725
1726 int
1727 db_FIRSTKEY(db)
1728         DB_File         db
1729         CODE:
1730         {
1731             DBTKEY      key ;
1732             DBT         value ;
1733
1734             DBT_clear(key) ; 
1735             DBT_clear(value) ; 
1736             CurrentDB = db ;
1737             RETVAL = do_SEQ(db, key, value, R_FIRST) ;
1738             ST(0) = sv_newmortal();
1739             OutputKey(ST(0), key) ;
1740         }
1741
1742 int
1743 db_NEXTKEY(db, key)
1744         DB_File         db
1745         DBTKEY          key
1746         CODE:
1747         {
1748             DBT         value ;
1749
1750             DBT_clear(value) ; 
1751             CurrentDB = db ;
1752             RETVAL = do_SEQ(db, key, value, R_NEXT) ;
1753             ST(0) = sv_newmortal();
1754             OutputKey(ST(0), key) ;
1755         }
1756
1757 #
1758 # These would be nice for RECNO
1759 #
1760
1761 int
1762 unshift(db, ...)
1763         DB_File         db
1764         ALIAS:          UNSHIFT = 1
1765         CODE:
1766         {
1767             DBTKEY      key ;
1768             DBT         value ;
1769             int         i ;
1770             int         One ;
1771             STRLEN      n_a;
1772
1773             DBT_clear(key) ; 
1774             DBT_clear(value) ; 
1775             CurrentDB = db ;
1776 #ifdef DB_VERSION_MAJOR
1777             /* get the first value */
1778             RETVAL = do_SEQ(db, key, value, DB_FIRST) ;  
1779             RETVAL = 0 ;
1780 #else
1781             RETVAL = -1 ;
1782 #endif
1783             for (i = items-1 ; i > 0 ; --i)
1784             {
1785                 value.data = SvPV(ST(i), n_a) ;
1786                 value.size = n_a ;
1787                 One = 1 ;
1788                 key.data = &One ;
1789                 key.size = sizeof(int) ;
1790 #ifdef DB_VERSION_MAJOR
1791                 RETVAL = (db->cursor->c_put)(db->cursor, &key, &value, DB_BEFORE) ;
1792 #else
1793                 RETVAL = (db->dbp->put)(db->dbp, &key, &value, R_IBEFORE) ;
1794 #endif
1795                 if (RETVAL != 0)
1796                     break;
1797             }
1798         }
1799         OUTPUT:
1800             RETVAL
1801
1802 I32
1803 pop(db)
1804         DB_File         db
1805         ALIAS:          POP = 1
1806         CODE:
1807         {
1808             DBTKEY      key ;
1809             DBT         value ;
1810
1811             DBT_clear(key) ; 
1812             DBT_clear(value) ; 
1813             CurrentDB = db ;
1814
1815             /* First get the final value */
1816             RETVAL = do_SEQ(db, key, value, R_LAST) ;    
1817             ST(0) = sv_newmortal();
1818             /* Now delete it */
1819             if (RETVAL == 0)
1820             {
1821                 /* the call to del will trash value, so take a copy now */
1822                 OutputValue(ST(0), value) ;
1823                 RETVAL = db_del(db, key, R_CURSOR) ;
1824                 if (RETVAL != 0) 
1825                     sv_setsv(ST(0), &PL_sv_undef); 
1826             }
1827         }
1828
1829 I32
1830 shift(db)
1831         DB_File         db
1832         ALIAS:          SHIFT = 1
1833         CODE:
1834         {
1835             DBT         value ;
1836             DBTKEY      key ;
1837
1838             DBT_clear(key) ; 
1839             DBT_clear(value) ; 
1840             CurrentDB = db ;
1841             /* get the first value */
1842             RETVAL = do_SEQ(db, key, value, R_FIRST) ;   
1843             ST(0) = sv_newmortal();
1844             /* Now delete it */
1845             if (RETVAL == 0)
1846             {
1847                 /* the call to del will trash value, so take a copy now */
1848                 OutputValue(ST(0), value) ;
1849                 RETVAL = db_del(db, key, R_CURSOR) ;
1850                 if (RETVAL != 0)
1851                     sv_setsv (ST(0), &PL_sv_undef) ;
1852             }
1853         }
1854
1855
1856 I32
1857 push(db, ...)
1858         DB_File         db
1859         ALIAS:          PUSH = 1
1860         CODE:
1861         {
1862             DBTKEY      key ;
1863             DBT         value ;
1864             DB *        Db = db->dbp ;
1865             int         i ;
1866             STRLEN      n_a;
1867             int         keyval ;
1868
1869             DBT_flags(key) ; 
1870             DBT_flags(value) ; 
1871             CurrentDB = db ;
1872             /* Set the Cursor to the Last element */
1873             RETVAL = do_SEQ(db, key, value, R_LAST) ;
1874 #ifndef DB_VERSION_MAJOR                                    
1875             if (RETVAL >= 0)
1876 #endif      
1877             {
1878                 if (RETVAL == 0)
1879                     keyval = *(int*)key.data ;
1880                 else
1881                     keyval = 0 ;
1882                 for (i = 1 ; i < items ; ++i)
1883                 {
1884                     value.data = SvPV(ST(i), n_a) ;
1885                     value.size = n_a ;
1886                     ++ keyval ;
1887                     key.data = &keyval ;
1888                     key.size = sizeof(int) ;
1889                     RETVAL = (Db->put)(Db, TXN &key, &value, 0) ;
1890                     if (RETVAL != 0)
1891                         break;
1892                 }
1893             }
1894         }
1895         OUTPUT:
1896             RETVAL
1897
1898 I32
1899 length(db)
1900         DB_File         db
1901         ALIAS:          FETCHSIZE = 1
1902         CODE:
1903             CurrentDB = db ;
1904             RETVAL = GetArrayLength(aTHX_ db) ;
1905         OUTPUT:
1906             RETVAL
1907
1908
1909 #
1910 # Now provide an interface to the rest of the DB functionality
1911 #
1912
1913 int
1914 db_del(db, key, flags=0)
1915         DB_File         db
1916         DBTKEY          key
1917         u_int           flags
1918         CODE:
1919           CurrentDB = db ;
1920           RETVAL = db_del(db, key, flags) ;
1921 #ifdef DB_VERSION_MAJOR
1922           if (RETVAL > 0)
1923             RETVAL = -1 ;
1924           else if (RETVAL == DB_NOTFOUND)
1925             RETVAL = 1 ;
1926 #endif
1927         OUTPUT:
1928           RETVAL
1929
1930
1931 int
1932 db_get(db, key, value, flags=0)
1933         DB_File         db
1934         DBTKEY          key
1935         DBT             value = NO_INIT
1936         u_int           flags
1937         CODE:
1938           CurrentDB = db ;
1939           DBT_clear(value) ; 
1940           RETVAL = db_get(db, key, value, flags) ;
1941 #ifdef DB_VERSION_MAJOR
1942           if (RETVAL > 0)
1943             RETVAL = -1 ;
1944           else if (RETVAL == DB_NOTFOUND)
1945             RETVAL = 1 ;
1946 #endif
1947         OUTPUT:
1948           RETVAL
1949           value
1950
1951 int
1952 db_put(db, key, value, flags=0)
1953         DB_File         db
1954         DBTKEY          key
1955         DBT             value
1956         u_int           flags
1957         CODE:
1958           CurrentDB = db ;
1959           RETVAL = db_put(db, key, value, flags) ;
1960 #ifdef DB_VERSION_MAJOR
1961           if (RETVAL > 0)
1962             RETVAL = -1 ;
1963           else if (RETVAL == DB_KEYEXIST)
1964             RETVAL = 1 ;
1965 #endif
1966         OUTPUT:
1967           RETVAL
1968           key           if (flagSet(flags, R_IAFTER) || flagSet(flags, R_IBEFORE)) OutputKey(ST(1), key);
1969
1970 int
1971 db_fd(db)
1972         DB_File         db
1973         int             status = 0 ;
1974         CODE:
1975           CurrentDB = db ;
1976 #ifdef DB_VERSION_MAJOR
1977           RETVAL = -1 ;
1978           status = (db->in_memory
1979                 ? -1 
1980                 : ((db->dbp)->fd)(db->dbp, &RETVAL) ) ;
1981           if (status != 0)
1982             RETVAL = -1 ;
1983 #else
1984           RETVAL = (db->in_memory
1985                 ? -1 
1986                 : ((db->dbp)->fd)(db->dbp) ) ;
1987 #endif
1988         OUTPUT:
1989           RETVAL
1990
1991 int
1992 db_sync(db, flags=0)
1993         DB_File         db
1994         u_int           flags
1995         CODE:
1996           CurrentDB = db ;
1997           RETVAL = db_sync(db, flags) ;
1998 #ifdef DB_VERSION_MAJOR
1999           if (RETVAL > 0)
2000             RETVAL = -1 ;
2001 #endif
2002         OUTPUT:
2003           RETVAL
2004
2005
2006 int
2007 db_seq(db, key, value, flags)
2008         DB_File         db
2009         DBTKEY          key 
2010         DBT             value = NO_INIT
2011         u_int           flags
2012         CODE:
2013           CurrentDB = db ;
2014           DBT_clear(value) ; 
2015           RETVAL = db_seq(db, key, value, flags);
2016 #ifdef DB_VERSION_MAJOR
2017           if (RETVAL > 0)
2018             RETVAL = -1 ;
2019           else if (RETVAL == DB_NOTFOUND)
2020             RETVAL = 1 ;
2021 #endif
2022         OUTPUT:
2023           RETVAL
2024           key
2025           value
2026
2027 #ifdef DBM_FILTERING
2028
2029 #define setFilter(type)                                 \
2030         {                                               \
2031             if (db->type)                               \
2032                 RETVAL = sv_mortalcopy(db->type) ;      \
2033             ST(0) = RETVAL ;                            \
2034             if (db->type && (code == &PL_sv_undef)) {   \
2035                 SvREFCNT_dec(db->type) ;                \
2036                 db->type = NULL ;                       \
2037             }                                           \
2038             else if (code) {                            \
2039                 if (db->type)                           \
2040                     sv_setsv(db->type, code) ;          \
2041                 else                                    \
2042                     db->type = newSVsv(code) ;          \
2043             }                                           \
2044         }
2045
2046
2047 SV *
2048 filter_fetch_key(db, code)
2049         DB_File         db
2050         SV *            code
2051         SV *            RETVAL = &PL_sv_undef ;
2052         CODE:
2053             setFilter(filter_fetch_key) ;
2054
2055 SV *
2056 filter_store_key(db, code)
2057         DB_File         db
2058         SV *            code
2059         SV *            RETVAL = &PL_sv_undef ;
2060         CODE:
2061             setFilter(filter_store_key) ;
2062
2063 SV *
2064 filter_fetch_value(db, code)
2065         DB_File         db
2066         SV *            code
2067         SV *            RETVAL = &PL_sv_undef ;
2068         CODE:
2069             setFilter(filter_fetch_value) ;
2070
2071 SV *
2072 filter_store_value(db, code)
2073         DB_File         db
2074         SV *            code
2075         SV *            RETVAL = &PL_sv_undef ;
2076         CODE:
2077             setFilter(filter_store_value) ;
2078
2079 #endif /* DBM_FILTERING */