source: gsdl/trunk/lib/gdbmclass.cpp@ 15598

Last change on this file since 15598 was 15598, checked in by mdewsnip, 16 years ago

(Adding new DB support) Moved some non-GDBM-specific code out of gdbmclass and into dbclass.

File size: 9.8 KB
Line 
1/**********************************************************************
2 *
3 * gdbmclass.cpp --
4 * Copyright (C) 1999-2008 The New Zealand Digital Library Project
5 *
6 * A component of the Greenstone digital library software
7 * from the New Zealand Digital Library Project at the
8 * University of Waikato, New Zealand.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 *********************************************************************/
25
26#include "gdbmclass.h"
27#include "unitool.h"
28#include "gsdlunicode.h"
29#include "OIDtools.h"
30
31
32gdbmclass::~gdbmclass()
33{
34 closedatabase();
35}
36
37// returns true if opened
38bool gdbmclass::opendatabase (const text_t &filename, int mode, int num_retrys,
39#ifdef __WIN32__
40 bool need_filelock
41#else
42 bool
43#endif
44 )
45{
46 text_t data_location;
47 int block_size = 512;
48
49 if (gdbmfile != NULL) {
50 if (openfile == filename) return true;
51 else closedatabase ();
52 }
53
54 openfile = filename;
55
56 // Map the DB mode values into GDBM mode values
57 int gdbm_mode = GDBM_READER;
58 if (mode == DB_WRITER)
59 {
60 gdbm_mode = GDBM_WRITER;
61 }
62 else if (mode == DB_WRITER_CREATE)
63 {
64 gdbm_mode = GDBM_WRCREAT;
65 }
66
67 char *namebuffer = filename.getcstr();
68 do {
69#ifdef __WIN32__
70 gdbmfile = gdbm_open (namebuffer, block_size, gdbm_mode, 00664, NULL, (need_filelock) ? 1 : 0);
71#else
72 gdbmfile = gdbm_open (namebuffer, block_size, gdbm_mode, 00664, NULL);
73#endif
74 --num_retrys;
75 } while (num_retrys>0 && gdbmfile==NULL &&
76 (gdbm_errno==GDBM_CANT_BE_READER || gdbm_errno==GDBM_CANT_BE_WRITER));
77 delete []namebuffer;
78
79 if (gdbmfile == NULL && logout != NULL) {
80 outconvertclass text_t2ascii;
81 (*logout) << text_t2ascii << "database open failed on: " << filename << "\n";
82 }
83
84 return (gdbmfile != NULL);
85}
86
87
88void gdbmclass::closedatabase ()
89{
90 if (gdbmfile == NULL) return;
91
92 gdbm_close (gdbmfile);
93 gdbmfile = NULL;
94 openfile.clear();
95}
96
97
98// returns true on success
99bool gdbmclass::setinfo (const text_t &key, const infodbclass &info)
100{
101 if (gdbmfile == NULL) return false;
102
103 text_t subkey;
104 text_t data;
105
106 // get all the keys and values
107 infodbclass::const_iterator info_here = info.begin();
108 infodbclass::const_iterator info_end = info.end();
109 while (info_here != info_end) {
110 // add the key
111 subkey.clear();
112 subkey.push_back('<');
113 text_t::const_iterator subkey_here = (*info_here).first.begin();
114 text_t::const_iterator subkey_end = (*info_here).first.end();
115 while (subkey_here != subkey_end) {
116 if (*subkey_here == '>') {
117 subkey.push_back('\\'); subkey.push_back('>');
118 } else if (*subkey_here == '\n') {
119 subkey.push_back('\\'); subkey.push_back('n');
120 } else if (*subkey_here == '\r') {
121 subkey.push_back('\\'); subkey.push_back('r');
122 } else if (*subkey_here == '\\') {
123 subkey.push_back('\\'); subkey.push_back('\\');
124 } else {
125 subkey.push_back (*subkey_here);
126 }
127 ++subkey_here;
128 }
129 subkey.push_back('>');
130
131 // add the values
132 text_tarray::const_iterator subvalue_here = (*info_here).second.begin();
133 text_tarray::const_iterator subvalue_end = (*info_here).second.end();
134 while (subvalue_here != subvalue_end) {
135 data += subkey;
136
137 text_t::const_iterator thissubvalue_here = (*subvalue_here).begin();
138 text_t::const_iterator thissubvalue_end = (*subvalue_here).end();
139 while (thissubvalue_here != thissubvalue_end) {
140 if (*thissubvalue_here == '>') {
141 data.push_back('\\'); data.push_back('>');
142 } else if (*thissubvalue_here == '\n') {
143 data.push_back('\\'); data.push_back('n');
144 } else if (*thissubvalue_here == '\r') {
145 data.push_back('\\'); data.push_back('r');
146 } else if (*thissubvalue_here == '\\') {
147 data.push_back('\\'); data.push_back('\\');
148 } else {
149 data.push_back (*thissubvalue_here);
150 }
151
152 ++thissubvalue_here;
153 }
154
155 data.push_back('\n');
156 ++subvalue_here;
157 }
158
159 ++info_here;
160 }
161
162 // store the value
163 datum key_data;
164 datum data_data;
165
166 // get a utf-8 encoded c string of the unicode key
167 key_data.dptr = (to_utf8(key)).getcstr();
168 if (key_data.dptr == NULL) {
169 if (logout != NULL) (*logout) << "gdbmclass: out of memory\n";
170 return false;
171 }
172 key_data.dsize = strlen (key_data.dptr);
173
174 data_data.dptr = (to_utf8(data)).getcstr();
175 if (data_data.dptr == NULL) {
176 if (logout != NULL) (*logout) << "gdbmclass: out of memory\n";
177 delete []key_data.dptr;
178 return false;
179 }
180 data_data.dsize = strlen (data_data.dptr);
181
182 int ret = gdbm_store (gdbmfile, key_data, data_data, GDBM_REPLACE);
183 delete []key_data.dptr;
184 delete []data_data.dptr;
185
186 return (ret == 0);
187}
188
189
190//returns true on success
191bool gdbmclass::setinfo (const text_t &key, const text_t &data)
192{
193 if (gdbmfile == NULL) return false;
194
195 // store the value
196 datum key_data;
197 datum data_data;
198
199 // get a utf-8 encoded c string of the unicode key
200 key_data.dptr = (to_utf8(key)).getcstr();
201 if (key_data.dptr == NULL) {
202 if (logout != NULL) (*logout) << "gdbmclass: out of memory\n";
203 return false;
204 }
205 key_data.dsize = strlen (key_data.dptr);
206
207 data_data.dptr = (to_utf8(data)).getcstr();
208 if (data_data.dptr == NULL) {
209 if (logout != NULL) (*logout) << "gdbmclass: out of memory\n";
210 delete []key_data.dptr;
211 return false;
212 }
213 data_data.dsize = strlen (data_data.dptr);
214
215 int ret = gdbm_store (gdbmfile, key_data, data_data, GDBM_REPLACE);
216 delete []key_data.dptr;
217 delete []data_data.dptr;
218
219 return (ret == 0);
220}
221
222
223void gdbmclass::deletekey (const text_t &key)
224{
225 if (gdbmfile == NULL) return;
226
227 // get a utf-8 encoded c string of the unicode key
228 datum key_data;
229 key_data.dptr = (to_utf8(key)).getcstr();
230 if (key_data.dptr == NULL) return;
231 key_data.dsize = strlen (key_data.dptr);
232
233 // delete the key
234 gdbm_delete (gdbmfile, key_data);
235
236 // free up the key memory
237 delete []key_data.dptr;
238}
239
240
241// getfirstkey and getnextkey are used for traversing the database
242// no insertions or deletions should be carried out while traversing
243// the database. when there are no keys left to visit in the database
244// an empty string is returned.
245text_t gdbmclass::getfirstkey ()
246{
247 if (gdbmfile == NULL) return g_EmptyText;
248
249 // get the first key
250 datum firstkey_data = gdbm_firstkey (gdbmfile);
251 if (firstkey_data.dptr == NULL) return g_EmptyText;
252
253 // convert it to text_t
254 text_t firstkey;
255 firstkey.setcarr (firstkey_data.dptr, firstkey_data.dsize);
256 free (firstkey_data.dptr);
257 return to_uni(firstkey); // convert to unicode
258}
259
260
261text_t gdbmclass::getnextkey (const text_t &key)
262{
263 if (gdbmfile == NULL || key.empty()) return g_EmptyText;
264
265 // get a utf-8 encoded c string of the unicode key
266 datum key_data;
267 key_data.dptr = (to_utf8(key)).getcstr();
268 if (key_data.dptr == NULL) return g_EmptyText;
269 key_data.dsize = strlen (key_data.dptr);
270
271 // get the next key
272 datum nextkey_data = gdbm_nextkey (gdbmfile, key_data);
273 if (nextkey_data.dptr == NULL) {
274 delete []key_data.dptr;
275 return g_EmptyText;
276 }
277
278 // convert it to text_t
279 text_t nextkey;
280 nextkey.setcarr (nextkey_data.dptr, nextkey_data.dsize);
281 free (nextkey_data.dptr);
282 delete []key_data.dptr;
283 return to_uni(nextkey); // convert to unicode
284}
285
286
287// returns true on success
288bool gdbmclass::getinfo (const text_t& key, infodbclass &info)
289{
290 text_t data;
291
292 if (!getkeydata (key, data)) return false;
293 text_t::iterator here = data.begin ();
294 text_t::iterator end = data.end ();
295
296 text_t ikey, ivalue;
297 info.clear (); // reset info
298
299 while (getinfoline (here, end, ikey, ivalue)) {
300 info.addinfo (ikey, ivalue);
301 }
302
303 return true;
304}
305
306
307// returns true if exists
308bool gdbmclass::exists (const text_t& key)
309{
310 text_t data;
311 return getkeydata (key, data);
312}
313
314
315// returns true on success
316bool gdbmclass::getkeydata (const text_t& key, text_t &data)
317{
318 datum key_data;
319 datum return_data;
320
321 if (gdbmfile == NULL) return false;
322
323 // get a utf-8 encoded c string of the unicode key
324 key_data.dptr = (to_utf8(key)).getcstr();
325 if (key_data.dptr == NULL) {
326 if (logout != NULL) (*logout) << "gdbmclass: out of memory\n";
327 return false;
328 }
329 key_data.dsize = strlen (key_data.dptr);
330
331 // fetch the result
332 return_data = gdbm_fetch (gdbmfile, key_data);
333 delete []key_data.dptr;
334
335 if (return_data.dptr == NULL) return false;
336
337 data.setcarr (return_data.dptr, return_data.dsize);
338 free (return_data.dptr);
339 data = to_uni(data); // convert to unicode
340
341 return true;
342}
343
344
345// returns true on success
346bool gdbmclass::getinfoline (text_t::iterator &here, text_t::iterator end,
347 text_t &key, text_t &value)
348{
349 key.clear();
350 value.clear();
351
352 // ignore white space
353 while (here != end && is_unicode_space (*here)) ++here;
354
355 // get the '<'
356 if (here == end || *here != '<') return false;
357 ++here;
358
359 // get the key
360 while (here != end && *here != '>') {
361 key.push_back(*here);
362 ++here;
363 }
364
365 // get the '>'
366 if (here == end || *here != '>') return false;
367 ++here;
368
369 // get the value
370 while (here != end && *here != '\n') {
371 if (*here == '\\') {
372 // found escape character
373 ++here;
374 if (here != end) {
375 if (*here == 'n') value.push_back ('\n');
376 else if (*here == 'r') value.push_back ('\r');
377 else value.push_back(*here);
378 }
379
380 } else {
381 // a normal character
382 value.push_back(*here);
383 }
384
385 ++here;
386 }
387
388 return true;
389}
Note: See TracBrowser for help on using the repository browser.