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

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

Removed a big block of duplicate code.

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