ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/staticperl/perl/ext/DB_File/DB_File.xs
Revision: 1.1
Committed: Thu Jun 30 14:26:44 2005 UTC (21 years, 3 months ago) by root
Branch: MAIN
CVS Tags: PERL-5-8-7, HEAD
Branch point for: PERL
Log Message:
*** empty log message ***

File Contents

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