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

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

(Adding new DB support) Tidied up getinfo().

File size: 9.6 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 if exists
118bool gdbmclass::exists (const text_t& key)
119{
120 text_t data;
121 return getkeydata (key, data);
122}
123
124
125// returns true on success
126bool gdbmclass::getinfo (const text_t& key, infodbclass &info)
127{
128 text_t data;
129 if (!getkeydata(key, data)) return false;
130
131 // Use getinfoline() to parse the data value into the infodbclass object
132 text_t::iterator data_iterator = data.begin();
133 text_t ikey, ivalue;
134 info.clear();
135 while (getinfoline(data_iterator, data.end(), ikey, ivalue))
136 {
137 info.addinfo(ikey, ivalue);
138 }
139
140 return true;
141}
142
143
144// returns true on success
145bool gdbmclass::getkeydata (const text_t& key, text_t &data)
146{
147 datum key_data;
148 datum return_data;
149
150 if (gdbmfile == NULL) return false;
151
152 // get a utf-8 encoded c string of the unicode key
153 key_data.dptr = (to_utf8(key)).getcstr();
154 if (key_data.dptr == NULL) {
155 if (logout != NULL) (*logout) << "gdbmclass: out of memory\n";
156 return false;
157 }
158 key_data.dsize = strlen (key_data.dptr);
159
160 // fetch the result
161 return_data = gdbm_fetch (gdbmfile, key_data);
162 delete []key_data.dptr;
163
164 if (return_data.dptr == NULL) return false;
165
166 data.setcarr (return_data.dptr, return_data.dsize);
167 free (return_data.dptr);
168 data = to_uni(data); // convert to unicode
169
170 return true;
171}
172
173
174// returns array of keys
175text_tarray gdbmclass::getkeys ()
176{
177 text_tarray keys;
178
179 text_t key = getfirstkey();
180 while (!key.empty())
181 {
182 keys.push_back(key);
183 key = getnextkey(key);
184 }
185
186 return keys;
187}
188
189
190// returns true on success
191bool gdbmclass::setinfo (const text_t &key, const infodbclass &info)
192{
193 if (gdbmfile == NULL) return false;
194
195 text_t subkey;
196 text_t data;
197
198 // get all the keys and values
199 infodbclass::const_iterator info_here = info.begin();
200 infodbclass::const_iterator info_end = info.end();
201 while (info_here != info_end) {
202 // add the key
203 subkey.clear();
204 subkey.push_back('<');
205 text_t::const_iterator subkey_here = (*info_here).first.begin();
206 text_t::const_iterator subkey_end = (*info_here).first.end();
207 while (subkey_here != subkey_end) {
208 if (*subkey_here == '>') {
209 subkey.push_back('\\'); subkey.push_back('>');
210 } else if (*subkey_here == '\n') {
211 subkey.push_back('\\'); subkey.push_back('n');
212 } else if (*subkey_here == '\r') {
213 subkey.push_back('\\'); subkey.push_back('r');
214 } else if (*subkey_here == '\\') {
215 subkey.push_back('\\'); subkey.push_back('\\');
216 } else {
217 subkey.push_back (*subkey_here);
218 }
219 ++subkey_here;
220 }
221 subkey.push_back('>');
222
223 // add the values
224 text_tarray::const_iterator subvalue_here = (*info_here).second.begin();
225 text_tarray::const_iterator subvalue_end = (*info_here).second.end();
226 while (subvalue_here != subvalue_end) {
227 data += subkey;
228
229 text_t::const_iterator thissubvalue_here = (*subvalue_here).begin();
230 text_t::const_iterator thissubvalue_end = (*subvalue_here).end();
231 while (thissubvalue_here != thissubvalue_end) {
232 if (*thissubvalue_here == '>') {
233 data.push_back('\\'); data.push_back('>');
234 } else if (*thissubvalue_here == '\n') {
235 data.push_back('\\'); data.push_back('n');
236 } else if (*thissubvalue_here == '\r') {
237 data.push_back('\\'); data.push_back('r');
238 } else if (*thissubvalue_here == '\\') {
239 data.push_back('\\'); data.push_back('\\');
240 } else {
241 data.push_back (*thissubvalue_here);
242 }
243
244 ++thissubvalue_here;
245 }
246
247 data.push_back('\n');
248 ++subvalue_here;
249 }
250
251 ++info_here;
252 }
253
254 return setkeydata(key, data);
255}
256
257
258// returns true on success
259bool gdbmclass::setkeydata (const text_t &key, const text_t &data)
260{
261 if (gdbmfile == NULL) return false;
262
263 // store the value
264 datum key_data;
265 datum data_data;
266
267 // get a utf-8 encoded c string of the unicode key
268 key_data.dptr = (to_utf8(key)).getcstr();
269 if (key_data.dptr == NULL) {
270 if (logout != NULL) (*logout) << "gdbmclass: out of memory\n";
271 return false;
272 }
273 key_data.dsize = strlen (key_data.dptr);
274
275 data_data.dptr = (to_utf8(data)).getcstr();
276 if (data_data.dptr == NULL) {
277 if (logout != NULL) (*logout) << "gdbmclass: out of memory\n";
278 delete []key_data.dptr;
279 return false;
280 }
281 data_data.dsize = strlen (data_data.dptr);
282
283 int ret = gdbm_store (gdbmfile, key_data, data_data, GDBM_REPLACE);
284 delete []key_data.dptr;
285 delete []data_data.dptr;
286
287 return (ret == 0);
288}
289
290
291// ----------------------------------------------------------------------------------------
292// GDBM-ONLY FUNCTIONS
293// ----------------------------------------------------------------------------------------
294
295// getfirstkey and getnextkey are used for traversing the database
296// no insertions or deletions should be carried out while traversing
297// the database. when there are no keys left to visit in the database
298// an empty string is returned.
299text_t gdbmclass::getfirstkey ()
300{
301 if (gdbmfile == NULL) return g_EmptyText;
302
303 // get the first key
304 datum firstkey_data = gdbm_firstkey (gdbmfile);
305 if (firstkey_data.dptr == NULL) return g_EmptyText;
306
307 // convert it to text_t
308 text_t firstkey;
309 firstkey.setcarr (firstkey_data.dptr, firstkey_data.dsize);
310 free (firstkey_data.dptr);
311 return to_uni(firstkey); // convert to unicode
312}
313
314
315text_t gdbmclass::getnextkey (const text_t &key)
316{
317 if (gdbmfile == NULL || key.empty()) return g_EmptyText;
318
319 // get a utf-8 encoded c string of the unicode key
320 datum key_data;
321 key_data.dptr = (to_utf8(key)).getcstr();
322 if (key_data.dptr == NULL) return g_EmptyText;
323 key_data.dsize = strlen (key_data.dptr);
324
325 // get the next key
326 datum nextkey_data = gdbm_nextkey (gdbmfile, key_data);
327 if (nextkey_data.dptr == NULL) {
328 delete []key_data.dptr;
329 return g_EmptyText;
330 }
331
332 // convert it to text_t
333 text_t nextkey;
334 nextkey.setcarr (nextkey_data.dptr, nextkey_data.dsize);
335 free (nextkey_data.dptr);
336 delete []key_data.dptr;
337 return to_uni(nextkey); // convert to unicode
338}
339
340
341// returns true on success
342bool gdbmclass::getinfoline (text_t::iterator &here, text_t::iterator end,
343 text_t &key, text_t &value)
344{
345 key.clear();
346 value.clear();
347
348 // ignore white space
349 while (here != end && is_unicode_space (*here)) ++here;
350
351 // get the '<'
352 if (here == end || *here != '<') return false;
353 ++here;
354
355 // get the key
356 while (here != end && *here != '>') {
357 key.push_back(*here);
358 ++here;
359 }
360
361 // get the '>'
362 if (here == end || *here != '>') return false;
363 ++here;
364
365 // get the value
366 while (here != end && *here != '\n') {
367 if (*here == '\\') {
368 // found escape character
369 ++here;
370 if (here != end) {
371 if (*here == 'n') value.push_back ('\n');
372 else if (*here == 'r') value.push_back ('\r');
373 else value.push_back(*here);
374 }
375
376 } else {
377 // a normal character
378 value.push_back(*here);
379 }
380
381 ++here;
382 }
383
384 return true;
385}
Note: See TracBrowser for help on using the repository browser.