This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
463f8e86150bd1f06e705d0501906f422d9c013f
[perl5.git] / ext / ODBM_File / ODBM_File.xs
1 #include "EXTERN.h"
2 #include "perl.h"
3 #include "XSUB.h"
4
5 #ifdef I_DBM
6 #  include <dbm.h>
7 #else
8 #  ifdef I_RPCSVC_DBM
9 #    include <rpcsvc/dbm.h>
10 #  endif
11 #endif
12
13 #ifndef HAS_DBMINIT_PROTO
14 int     dbminit(char* filename);
15 int     dbmclose(void);
16 datum   fetch(datum key);
17 int     store(datum key, datum dat);
18 int     delete(datum key); 
19 datum   firstkey(void);
20 datum   nextkey(datum key);
21 #endif
22
23 #ifdef DBM_BUG_DUPLICATE_FREE 
24 /*
25  * DBM on at least Ultrix and HPUX call dbmclose() from dbminit(),
26  * resulting in duplicate free() because dbmclose() does *not*
27  * check if it has already been called for this DBM.
28  * If some malloc/free calls have been done between dbmclose() and
29  * the next dbminit(), the memory might be used for something else when
30  * it is freed.
31  * Verified to work on ultrix4.3.  Probably will work on HP/UX.
32  * Set DBM_BUG_DUPLICATE_FREE in the extension hint file.
33  */
34 /* Close the previous dbm, and fail to open a new dbm */
35 #define dbmclose()      ((void) dbminit("/non/exist/ent"))
36 #endif
37
38 #include <fcntl.h>
39
40 #define fetch_key 0
41 #define store_key 1
42 #define fetch_value 2
43 #define store_value 3
44
45 typedef struct {
46         void *  dbp ;
47         SV *    filter[4];
48         int     filtering ;
49         } ODBM_File_type;
50
51 typedef ODBM_File_type * ODBM_File ;
52 typedef datum datum_key ;
53 typedef datum datum_key_copy ;
54 typedef datum datum_value ;
55
56 #define odbm_FETCH(db,key)                      fetch(key)
57 #define odbm_STORE(db,key,value,flags)          store(key,value)
58 #define odbm_DELETE(db,key)                     delete(key)
59 #define odbm_FIRSTKEY(db)                       firstkey()
60 #define odbm_NEXTKEY(db,key)                    nextkey(key)
61
62 #define MY_CXT_KEY "ODBM_File::_guts" XS_VERSION
63
64 typedef struct {
65     int         x_dbmrefcnt;
66 } my_cxt_t;
67
68 START_MY_CXT
69
70 #define dbmrefcnt       (MY_CXT.x_dbmrefcnt)
71
72 #ifndef DBM_REPLACE
73 #define DBM_REPLACE 0
74 #endif
75
76 MODULE = ODBM_File      PACKAGE = ODBM_File     PREFIX = odbm_
77
78 BOOT:
79 {
80     MY_CXT_INIT;
81 }
82
83 ODBM_File
84 odbm_TIEHASH(dbtype, filename, flags, mode)
85         char *          dbtype
86         char *          filename
87         int             flags
88         int             mode
89         CODE:
90         {
91             char *tmpbuf;
92             void * dbp ;
93             dMY_CXT;
94
95             if (dbmrefcnt++)
96                 croak("Old dbm can only open one database");
97             Newx(tmpbuf, strlen(filename) + 5, char);
98             SAVEFREEPV(tmpbuf);
99             sprintf(tmpbuf,"%s.dir",filename);
100             if (stat(tmpbuf, &PL_statbuf) < 0) {
101                 if (flags & O_CREAT) {
102                     if (mode < 0 || close(creat(tmpbuf,mode)) < 0)
103                         croak("ODBM_File: Can't create %s", filename);
104                     sprintf(tmpbuf,"%s.pag",filename);
105                     if (close(creat(tmpbuf,mode)) < 0)
106                         croak("ODBM_File: Can't create %s", filename);
107                 }
108                 else
109                     croak("ODBM_FILE: Can't open %s", filename);
110             }
111             dbp = (void*)(dbminit(filename) >= 0 ? &dbmrefcnt : 0);
112             RETVAL = (ODBM_File)safecalloc(1, sizeof(ODBM_File_type));
113             RETVAL->dbp = dbp ;
114             ST(0) = sv_mortalcopy(&PL_sv_undef);
115             sv_setptrobj(ST(0), RETVAL, dbtype);
116         }
117
118 void
119 DESTROY(db)
120         ODBM_File       db
121         PREINIT:
122         dMY_CXT;
123         int i = store_value;
124         CODE:
125         dbmrefcnt--;
126         dbmclose();
127         do {
128             if (db->filter[i])
129                 SvREFCNT_dec(db->filter[i]);
130         } while (i-- > 0);
131         safefree(db);
132
133 datum_value
134 odbm_FETCH(db, key)
135         ODBM_File       db
136         datum_key_copy  key
137
138 int
139 odbm_STORE(db, key, value, flags = DBM_REPLACE)
140         ODBM_File       db
141         datum_key       key
142         datum_value     value
143         int             flags
144     CLEANUP:
145         if (RETVAL) {
146             if (RETVAL < 0 && errno == EPERM)
147                 croak("No write permission to odbm file");
148             croak("odbm store returned %d, errno %d, key \"%s\"",
149                         RETVAL,errno,key.dptr);
150         }
151
152 int
153 odbm_DELETE(db, key)
154         ODBM_File       db
155         datum_key       key
156
157 datum_key
158 odbm_FIRSTKEY(db)
159         ODBM_File       db
160
161 datum_key
162 odbm_NEXTKEY(db, key)
163         ODBM_File       db
164         datum_key       key
165
166
167 #define setFilter(type)                                 \
168         {                                               \
169             if (db->type)                               \
170                 RETVAL = sv_mortalcopy(db->type) ;      \
171             ST(0) = RETVAL ;                            \
172             if (db->type && (code == &PL_sv_undef)) {   \
173                 SvREFCNT_dec(db->type) ;                \
174                 db->type = Nullsv ;                     \
175             }                                           \
176             else if (code) {                            \
177                 if (db->type)                           \
178                     sv_setsv(db->type, code) ;          \
179                 else                                    \
180                     db->type = newSVsv(code) ;          \
181             }                                           \
182         }
183
184
185
186 SV *
187 filter_fetch_key(db, code)
188         ODBM_File       db
189         SV *            code
190         SV *            RETVAL = &PL_sv_undef ;
191         ALIAS:
192         ODBM_File::filter_fetch_key = fetch_key
193         ODBM_File::filter_store_key = store_key
194         ODBM_File::filter_fetch_value = fetch_value
195         ODBM_File::filter_store_value = store_value
196         CODE:
197             DBM_setFilter(db->filter[ix], code);