root/gsdl/trunk/lib/gdbmclass.cpp @ 15644

Revision 15644, 10.2 KB (checked in by mdewsnip, 12 years ago)

Rearranging functions and tidying up.

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  // 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// returns true on success
284bool gdbmclass::setinfo (const text_t &key, const text_t &data)
285{
286  if (gdbmfile == NULL) return false;
287 
288  // store the value
289  datum key_data;
290  datum data_data;
291
292  // get a utf-8 encoded c string of the unicode key
293  key_data.dptr = (to_utf8(key)).getcstr();
294  if (key_data.dptr == NULL) {
295    if (logout != NULL) (*logout) << "gdbmclass: out of memory\n";
296    return false;
297  }
298  key_data.dsize = strlen (key_data.dptr);
299
300  data_data.dptr = (to_utf8(data)).getcstr();
301  if (data_data.dptr == NULL) {
302    if (logout != NULL) (*logout) << "gdbmclass: out of memory\n";
303    delete []key_data.dptr;
304    return false;
305  }
306  data_data.dsize = strlen (data_data.dptr);
307
308  int ret = gdbm_store (gdbmfile, key_data, data_data, GDBM_REPLACE);
309  delete []key_data.dptr;
310  delete []data_data.dptr;
311
312  return (ret == 0);
313}
314
315
316// ----------------------------------------------------------------------------------------
317//   GDBM-ONLY FUNCTIONS
318// ----------------------------------------------------------------------------------------
319
320// getfirstkey and getnextkey are used for traversing the database
321// no insertions or deletions should be carried out while traversing
322// the database. when there are no keys left to visit in the database
323// an empty string is returned.
324text_t gdbmclass::getfirstkey ()
325{
326  if (gdbmfile == NULL) return g_EmptyText;
327
328  // get the first key
329  datum firstkey_data = gdbm_firstkey (gdbmfile);
330  if (firstkey_data.dptr == NULL) return g_EmptyText;
331
332  // convert it to text_t
333  text_t firstkey;
334  firstkey.setcarr (firstkey_data.dptr, firstkey_data.dsize);
335  free (firstkey_data.dptr);
336  return to_uni(firstkey);  // convert to unicode
337}
338
339
340text_t gdbmclass::getnextkey (const text_t &key)
341{
342  if (gdbmfile == NULL || key.empty()) return g_EmptyText;
343
344  // get a utf-8 encoded c string of the unicode key
345  datum key_data;
346  key_data.dptr = (to_utf8(key)).getcstr();
347  if (key_data.dptr == NULL) return g_EmptyText;
348  key_data.dsize = strlen (key_data.dptr);
349 
350  // get the next key
351  datum nextkey_data = gdbm_nextkey (gdbmfile, key_data);
352  if (nextkey_data.dptr == NULL) {
353    delete []key_data.dptr;
354    return g_EmptyText;
355  }
356
357  // convert it to text_t
358  text_t nextkey;
359  nextkey.setcarr (nextkey_data.dptr, nextkey_data.dsize);
360  free (nextkey_data.dptr);
361  delete []key_data.dptr;
362  return to_uni(nextkey);  // convert to unicode
363}
364
365
366// returns true on success
367bool gdbmclass::getinfoline (text_t::iterator &here, text_t::iterator end,
368                 text_t &key, text_t &value)
369{
370  key.clear();
371  value.clear();
372
373  // ignore white space
374  while (here != end && is_unicode_space (*here)) ++here;
375
376  // get the '<'
377  if (here == end || *here != '<') return false;
378  ++here;
379 
380  // get the key
381  while (here != end && *here != '>') {
382    key.push_back(*here);
383    ++here;
384  }
385 
386  // get the '>'
387  if (here == end || *here != '>') return false;
388  ++here;
389 
390  // get the value
391  while (here != end && *here != '\n') {
392    if (*here == '\\') {
393      // found escape character
394      ++here;
395      if (here != end) {
396    if (*here == 'n') value.push_back ('\n');
397    else if (*here == 'r') value.push_back ('\r');
398    else value.push_back(*here);
399      }
400
401    } else {
402      // a normal character
403      value.push_back(*here);
404    }
405
406    ++here;
407  }
408
409  return true;
410}
Note: See TracBrowser for help on using the browser.