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

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

(Adding new DB support) Replaced the "getfirstkey()" and "getnextkey()" functions in dbclass with "getkeys()" (which returns them all). These functions were only used in userdb.cpp, and having the one function is simpler without being (much) less efficient. Also, implementing getkeys() for the new sql db classes will be easier than getfirstkey() and getnextkey().

File size: 10.0 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
241text_tarray gdbmclass::getkeys ()
242{
243 text_tarray keys;
244
245 text_t key = getfirstkey();
246 while (!key.empty())
247 {
248 keys.push_back(key);
249 key = getnextkey(key);
250 }
251
252 return keys;
253}
254
255
256// getfirstkey and getnextkey are used for traversing the database
257// no insertions or deletions should be carried out while traversing
258// the database. when there are no keys left to visit in the database
259// an empty string is returned.
260text_t gdbmclass::getfirstkey ()
261{
262 if (gdbmfile == NULL) return g_EmptyText;
263
264 // get the first key
265 datum firstkey_data = gdbm_firstkey (gdbmfile);
266 if (firstkey_data.dptr == NULL) return g_EmptyText;
267
268 // convert it to text_t
269 text_t firstkey;
270 firstkey.setcarr (firstkey_data.dptr, firstkey_data.dsize);
271 free (firstkey_data.dptr);
272 return to_uni(firstkey); // convert to unicode
273}
274
275
276text_t gdbmclass::getnextkey (const text_t &key)
277{
278 if (gdbmfile == NULL || key.empty()) return g_EmptyText;
279
280 // get a utf-8 encoded c string of the unicode key
281 datum key_data;
282 key_data.dptr = (to_utf8(key)).getcstr();
283 if (key_data.dptr == NULL) return g_EmptyText;
284 key_data.dsize = strlen (key_data.dptr);
285
286 // get the next key
287 datum nextkey_data = gdbm_nextkey (gdbmfile, key_data);
288 if (nextkey_data.dptr == NULL) {
289 delete []key_data.dptr;
290 return g_EmptyText;
291 }
292
293 // convert it to text_t
294 text_t nextkey;
295 nextkey.setcarr (nextkey_data.dptr, nextkey_data.dsize);
296 free (nextkey_data.dptr);
297 delete []key_data.dptr;
298 return to_uni(nextkey); // convert to unicode
299}
300
301
302// returns true on success
303bool gdbmclass::getinfo (const text_t& key, infodbclass &info)
304{
305 text_t data;
306
307 if (!getkeydata (key, data)) return false;
308 text_t::iterator here = data.begin ();
309 text_t::iterator end = data.end ();
310
311 text_t ikey, ivalue;
312 info.clear (); // reset info
313
314 while (getinfoline (here, end, ikey, ivalue)) {
315 info.addinfo (ikey, ivalue);
316 }
317
318 return true;
319}
320
321
322// returns true if exists
323bool gdbmclass::exists (const text_t& key)
324{
325 text_t data;
326 return getkeydata (key, data);
327}
328
329
330// returns true on success
331bool gdbmclass::getkeydata (const text_t& key, text_t &data)
332{
333 datum key_data;
334 datum return_data;
335
336 if (gdbmfile == NULL) return false;
337
338 // get a utf-8 encoded c string of the unicode key
339 key_data.dptr = (to_utf8(key)).getcstr();
340 if (key_data.dptr == NULL) {
341 if (logout != NULL) (*logout) << "gdbmclass: out of memory\n";
342 return false;
343 }
344 key_data.dsize = strlen (key_data.dptr);
345
346 // fetch the result
347 return_data = gdbm_fetch (gdbmfile, key_data);
348 delete []key_data.dptr;
349
350 if (return_data.dptr == NULL) return false;
351
352 data.setcarr (return_data.dptr, return_data.dsize);
353 free (return_data.dptr);
354 data = to_uni(data); // convert to unicode
355
356 return true;
357}
358
359
360// returns true on success
361bool gdbmclass::getinfoline (text_t::iterator &here, text_t::iterator end,
362 text_t &key, text_t &value)
363{
364 key.clear();
365 value.clear();
366
367 // ignore white space
368 while (here != end && is_unicode_space (*here)) ++here;
369
370 // get the '<'
371 if (here == end || *here != '<') return false;
372 ++here;
373
374 // get the key
375 while (here != end && *here != '>') {
376 key.push_back(*here);
377 ++here;
378 }
379
380 // get the '>'
381 if (here == end || *here != '>') return false;
382 ++here;
383
384 // get the value
385 while (here != end && *here != '\n') {
386 if (*here == '\\') {
387 // found escape character
388 ++here;
389 if (here != end) {
390 if (*here == 'n') value.push_back ('\n');
391 else if (*here == 'r') value.push_back ('\r');
392 else value.push_back(*here);
393 }
394
395 } else {
396 // a normal character
397 value.push_back(*here);
398 }
399
400 ++here;
401 }
402
403 return true;
404}
Note: See TracBrowser for help on using the repository browser.