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

Revision 15630, 10.0 KB (checked in by mdewsnip, 12 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().

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 browser.