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

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

(Adding new DB support) Moved the exists() function into dbclass because it can be shared between gdbmclass and sqlitedbclass.

File size: 9.5 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
38// returns true if opened
39bool gdbmclass::opendatabase (const text_t &filename, int mode, int num_retrys,
40#ifdef __WIN32__
41 bool need_filelock
42#else
43 bool
44#endif
45 )
46{
47 text_t data_location;
48 int block_size = 512;
49
50 if (gdbmfile != NULL) {
51 if (openfile == filename) return true;
52 else closedatabase ();
53 }
54
55 openfile = filename;
56
57 // Map the DB mode values into GDBM mode values
58 int gdbm_mode = GDBM_READER;
59 if (mode == DB_WRITER)
60 {
61 gdbm_mode = GDBM_WRITER;
62 }
63 else if (mode == DB_WRITER_CREATE)
64 {
65 gdbm_mode = GDBM_WRCREAT;
66 }
67
68 char *namebuffer = filename.getcstr();
69 do {
70#ifdef __WIN32__
71 gdbmfile = gdbm_open (namebuffer, block_size, gdbm_mode, 00664, NULL, (need_filelock) ? 1 : 0);
72#else
73 gdbmfile = gdbm_open (namebuffer, block_size, gdbm_mode, 00664, NULL);
74#endif
75 --num_retrys;
76 } while (num_retrys>0 && gdbmfile==NULL &&
77 (gdbm_errno==GDBM_CANT_BE_READER || gdbm_errno==GDBM_CANT_BE_WRITER));
78 delete []namebuffer;
79
80 if (gdbmfile == NULL && logout != NULL) {
81 outconvertclass text_t2ascii;
82 (*logout) << text_t2ascii << "database open failed on: " << filename << "\n";
83 }
84
85 return (gdbmfile != NULL);
86}
87
88
89void gdbmclass::closedatabase ()
90{
91 if (gdbmfile == NULL) return;
92
93 gdbm_close (gdbmfile);
94 gdbmfile = NULL;
95 openfile.clear();
96}
97
98
99void gdbmclass::deletekey (const text_t &key)
100{
101 if (gdbmfile == NULL) return;
102
103 // get a utf-8 encoded c string of the unicode key
104 datum key_data;
105 key_data.dptr = (to_utf8(key)).getcstr();
106 if (key_data.dptr == NULL) return;
107 key_data.dsize = strlen (key_data.dptr);
108
109 // delete the key
110 gdbm_delete (gdbmfile, key_data);
111
112 // free up the key memory
113 delete []key_data.dptr;
114}
115
116
117// returns true on success
118bool gdbmclass::getinfo (const text_t& key, infodbclass &info)
119{
120 text_t data;
121 if (!getkeydata(key, data)) return false;
122
123 // Use getinfoline() to parse the data value into the infodbclass object
124 text_t::iterator data_iterator = data.begin();
125 text_t ikey, ivalue;
126 info.clear();
127 while (getinfoline(data_iterator, data.end(), ikey, ivalue))
128 {
129 info.addinfo(ikey, ivalue);
130 }
131
132 return true;
133}
134
135
136// returns true on success
137bool gdbmclass::getkeydata (const text_t& key, text_t &data)
138{
139 datum key_data;
140 datum return_data;
141
142 if (gdbmfile == NULL) return false;
143
144 // get a utf-8 encoded c string of the unicode key
145 key_data.dptr = (to_utf8(key)).getcstr();
146 if (key_data.dptr == NULL) {
147 if (logout != NULL) (*logout) << "gdbmclass: out of memory\n";
148 return false;
149 }
150 key_data.dsize = strlen (key_data.dptr);
151
152 // fetch the result
153 return_data = gdbm_fetch (gdbmfile, key_data);
154 delete []key_data.dptr;
155
156 if (return_data.dptr == NULL) return false;
157
158 data.setcarr (return_data.dptr, return_data.dsize);
159 free (return_data.dptr);
160 data = to_uni(data); // convert to unicode
161
162 return true;
163}
164
165
166// returns array of keys
167text_tarray gdbmclass::getkeys ()
168{
169 text_tarray keys;
170
171 text_t key = getfirstkey();
172 while (!key.empty())
173 {
174 keys.push_back(key);
175 key = getnextkey(key);
176 }
177
178 return keys;
179}
180
181
182// returns true on success
183bool gdbmclass::setinfo (const text_t &key, const infodbclass &info)
184{
185 if (gdbmfile == NULL) return false;
186
187 text_t subkey;
188 text_t data;
189
190 // get all the keys and values
191 infodbclass::const_iterator info_here = info.begin();
192 infodbclass::const_iterator info_end = info.end();
193 while (info_here != info_end) {
194 // add the key
195 subkey.clear();
196 subkey.push_back('<');
197 text_t::const_iterator subkey_here = (*info_here).first.begin();
198 text_t::const_iterator subkey_end = (*info_here).first.end();
199 while (subkey_here != subkey_end) {
200 if (*subkey_here == '>') {
201 subkey.push_back('\\'); subkey.push_back('>');
202 } else if (*subkey_here == '\n') {
203 subkey.push_back('\\'); subkey.push_back('n');
204 } else if (*subkey_here == '\r') {
205 subkey.push_back('\\'); subkey.push_back('r');
206 } else if (*subkey_here == '\\') {
207 subkey.push_back('\\'); subkey.push_back('\\');
208 } else {
209 subkey.push_back (*subkey_here);
210 }
211 ++subkey_here;
212 }
213 subkey.push_back('>');
214
215 // add the values
216 text_tarray::const_iterator subvalue_here = (*info_here).second.begin();
217 text_tarray::const_iterator subvalue_end = (*info_here).second.end();
218 while (subvalue_here != subvalue_end) {
219 data += subkey;
220
221 text_t::const_iterator thissubvalue_here = (*subvalue_here).begin();
222 text_t::const_iterator thissubvalue_end = (*subvalue_here).end();
223 while (thissubvalue_here != thissubvalue_end) {
224 if (*thissubvalue_here == '>') {
225 data.push_back('\\'); data.push_back('>');
226 } else if (*thissubvalue_here == '\n') {
227 data.push_back('\\'); data.push_back('n');
228 } else if (*thissubvalue_here == '\r') {
229 data.push_back('\\'); data.push_back('r');
230 } else if (*thissubvalue_here == '\\') {
231 data.push_back('\\'); data.push_back('\\');
232 } else {
233 data.push_back (*thissubvalue_here);
234 }
235
236 ++thissubvalue_here;
237 }
238
239 data.push_back('\n');
240 ++subvalue_here;
241 }
242
243 ++info_here;
244 }
245
246 return setkeydata(key, data);
247}
248
249
250// returns true on success
251bool gdbmclass::setkeydata (const text_t &key, const text_t &data)
252{
253 if (gdbmfile == NULL) return false;
254
255 // store the value
256 datum key_data;
257 datum data_data;
258
259 // get a utf-8 encoded c string of the unicode key
260 key_data.dptr = (to_utf8(key)).getcstr();
261 if (key_data.dptr == NULL) {
262 if (logout != NULL) (*logout) << "gdbmclass: out of memory\n";
263 return false;
264 }
265 key_data.dsize = strlen (key_data.dptr);
266
267 data_data.dptr = (to_utf8(data)).getcstr();
268 if (data_data.dptr == NULL) {
269 if (logout != NULL) (*logout) << "gdbmclass: out of memory\n";
270 delete []key_data.dptr;
271 return false;
272 }
273 data_data.dsize = strlen (data_data.dptr);
274
275 int ret = gdbm_store (gdbmfile, key_data, data_data, GDBM_REPLACE);
276 delete []key_data.dptr;
277 delete []data_data.dptr;
278
279 return (ret == 0);
280}
281
282
283// ----------------------------------------------------------------------------------------
284// GDBM-ONLY FUNCTIONS
285// ----------------------------------------------------------------------------------------
286
287// getfirstkey and getnextkey are used for traversing the database
288// no insertions or deletions should be carried out while traversing
289// the database. when there are no keys left to visit in the database
290// an empty string is returned.
291text_t gdbmclass::getfirstkey ()
292{
293 if (gdbmfile == NULL) return g_EmptyText;
294
295 // get the first key
296 datum firstkey_data = gdbm_firstkey (gdbmfile);
297 if (firstkey_data.dptr == NULL) return g_EmptyText;
298
299 // convert it to text_t
300 text_t firstkey;
301 firstkey.setcarr (firstkey_data.dptr, firstkey_data.dsize);
302 free (firstkey_data.dptr);
303 return to_uni(firstkey); // convert to unicode
304}
305
306
307text_t gdbmclass::getnextkey (const text_t &key)
308{
309 if (gdbmfile == NULL || key.empty()) return g_EmptyText;
310
311 // get a utf-8 encoded c string of the unicode key
312 datum key_data;
313 key_data.dptr = (to_utf8(key)).getcstr();
314 if (key_data.dptr == NULL) return g_EmptyText;
315 key_data.dsize = strlen (key_data.dptr);
316
317 // get the next key
318 datum nextkey_data = gdbm_nextkey (gdbmfile, key_data);
319 if (nextkey_data.dptr == NULL) {
320 delete []key_data.dptr;
321 return g_EmptyText;
322 }
323
324 // convert it to text_t
325 text_t nextkey;
326 nextkey.setcarr (nextkey_data.dptr, nextkey_data.dsize);
327 free (nextkey_data.dptr);
328 delete []key_data.dptr;
329 return to_uni(nextkey); // convert to unicode
330}
331
332
333// returns true on success
334bool gdbmclass::getinfoline (text_t::iterator &here, text_t::iterator end,
335 text_t &key, text_t &value)
336{
337 key.clear();
338 value.clear();
339
340 // ignore white space
341 while (here != end && is_unicode_space (*here)) ++here;
342
343 // get the '<'
344 if (here == end || *here != '<') return false;
345 ++here;
346
347 // get the key
348 while (here != end && *here != '>') {
349 key.push_back(*here);
350 ++here;
351 }
352
353 // get the '>'
354 if (here == end || *here != '>') return false;
355 ++here;
356
357 // get the value
358 while (here != end && *here != '\n') {
359 if (*here == '\\') {
360 // found escape character
361 ++here;
362 if (here != end) {
363 if (*here == 'n') value.push_back ('\n');
364 else if (*here == 'r') value.push_back ('\r');
365 else value.push_back(*here);
366 }
367
368 } else {
369 // a normal character
370 value.push_back(*here);
371 }
372
373 ++here;
374 }
375
376 return true;
377}
Note: See TracBrowser for help on using the repository browser.