root/gsdl/trunk/common-src/src/lib/gdbmclass.cpp @ 17757

Revision 17757, 8.4 KB (checked in by ak19, 11 years ago)

The output for testing for perl on Linux/Mac (prior to converting txtgz to the database file) goes to stdout and ruins the page generated by the browser. Now using redirection of STDOUT to STDIN, it works on Linux. Need to test on Windows (and Mac?).

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 "gsdltools.h"
28#include "gsdlunicode.h"
29#include "fileutil.h"
30#include "stdlib.h"
31
32
33
34gdbmclass::~gdbmclass()
35{
36  closedatabase();
37}
38
39
40// returns true if opened
41bool gdbmclass::opendatabase (const text_t &filename, int mode, int num_retrys,
42#ifdef __WIN32__
43                  bool need_filelock
44#else
45                              bool
46#endif
47                  )
48{
49
50  text_t data_location;
51  int block_size = 512;
52 
53  if (gdbmfile != NULL) {
54    if (openfile == filename) return true;
55    else closedatabase ();
56  }
57
58  openfile = filename;
59
60  // Map the DB mode values into GDBM mode values
61  int gdbm_mode = GDBM_READER;
62  if (mode == DB_WRITER)
63  {
64    gdbm_mode = GDBM_WRITER;
65  }
66  else if (mode == DB_WRITER_CREATE)
67  {
68    gdbm_mode = GDBM_WRCREAT;
69  }
70
71  if (gdbm_mode == GDBM_READER) {
72    // Looking to read in the database
73    // => check to see if .ldb/.bdb file already there
74    // if not (first time) then generate using txt2db
75    if (!file_exists(filename)) {
76
77      // need to generate architecture native GDBM file using txt2db
78
79      // replace sought after gdbm filename ext with ".txt.gz"
80
81      text_t::const_iterator begin = filename.begin();
82      text_t::const_iterator end= filename.end();
83      text_t::const_iterator here = end;
84
85      bool found_ext = false;
86
87      while (here != begin) {
88    if (*here == '.') {
89      found_ext = true;
90      break;
91    }
92    here--;
93      }
94     
95      text_t filename_root;
96
97      if (found_ext) {
98    filename_root = substr(begin,here);
99      }
100      else {
101    filename_root = filename;
102      }
103
104      text_t txtgz_filename = filename_root + ".txt.gz";
105      if (file_exists(txtgz_filename))
106      {
107    //text_t cmd = "gzip --decompress --to-stdout \"" + txtgz_filename + "\"";
108    //cmd += " | txt2db \"" + filename + "\"";
109
110    // Test to make sure Perl is on the path
111    // On Linux, the output of the test goes to STDOUT so redirect it to STDERR
112    text_t cmd_test = "perl -v 1>&2";
113    int rv_test = gsdl_system(cmd_test, true, cerr);
114    if (rv_test != 0) {
115      cerr << "Tried to find Perl. Return exit value of running "
116           << cmd_test <<": "<< rv_test << ", (expected this to be 0)" << endl;
117      cerr << "Check that Perl is set in your environment variable PATH." << endl;
118      cerr << "At present, PATH=" << getenv("PATH") << endl;
119    }
120
121    text_t cmd = "perl -S txtgz-to-gdbm.pl \"" + txtgz_filename + "\" \"" + filename + "\"";
122    int rv = gsdl_system(cmd, true, cerr);
123    // For some reason, launching this command with gsdl_system() still returns 1
124    // even when it returns 0 when run from the command-line. We can check whether
125    // we succeeded by looking at whether the output database file was created.
126    if (rv != 0) {
127      cerr << "Warning, non-zero return value on running command \""
128           << cmd << "\": " << rv << endl;
129      if (!file_exists(filename)) {
130        cerr << "Tried to run command \""<<cmd<<"\", but it failed" << endl;
131      }
132    }   
133      }
134    }
135  }
136
137  char *namebuffer = filename.getcstr();
138  do {
139#ifdef __WIN32__
140    gdbmfile = gdbm_open (namebuffer, block_size, gdbm_mode, 00664, NULL, (need_filelock) ? 1 : 0);
141#else
142    gdbmfile = gdbm_open (namebuffer, block_size, gdbm_mode, 00664, NULL);
143#endif
144    --num_retrys;
145  } while (num_retrys>0 && gdbmfile==NULL &&
146       (gdbm_errno==GDBM_CANT_BE_READER || gdbm_errno==GDBM_CANT_BE_WRITER));
147  delete []namebuffer;
148 
149  if (gdbmfile == NULL && logout != NULL) {
150    outconvertclass text_t2ascii;
151    (*logout) << text_t2ascii << "database open failed on: " << filename << "\n";
152  }
153
154  return (gdbmfile != NULL);
155}
156
157
158void gdbmclass::closedatabase ()
159{
160  if (gdbmfile == NULL) return;
161 
162  gdbm_close (gdbmfile);
163  gdbmfile = NULL;
164  openfile.clear();
165}
166
167
168void gdbmclass::deletekey (const text_t &key)
169{
170  if (gdbmfile == NULL) return;
171
172  // get a utf-8 encoded c string of the unicode key
173  datum key_data;
174  key_data.dptr = (to_utf8(key)).getcstr();
175  if (key_data.dptr == NULL) return;
176  key_data.dsize = strlen (key_data.dptr);
177
178  // delete the key
179  gdbm_delete (gdbmfile, key_data);
180
181  // free up the key memory
182  delete []key_data.dptr;
183}
184
185
186// returns file extension string
187text_t gdbmclass::getfileextension ()
188{
189  if (littleEndian()) return ".ldb";
190  return ".bdb";
191}
192
193
194// returns true on success
195bool gdbmclass::getkeydata (const text_t& key, text_t &data)
196{
197  datum key_data;
198  datum return_data;
199
200  if (gdbmfile == NULL) return false;
201 
202  // get a utf-8 encoded c string of the unicode key
203  key_data.dptr = (to_utf8(key)).getcstr();
204  if (key_data.dptr == NULL) {
205    if (logout != NULL) (*logout) << "gdbmclass: out of memory" << endl;
206    return false;
207  }
208  key_data.dsize = strlen (key_data.dptr);
209 
210  // fetch the result
211  return_data = gdbm_fetch (gdbmfile, key_data);
212  delete []key_data.dptr;
213 
214  if (return_data.dptr == NULL) return false;
215
216  data.setcarr (return_data.dptr, return_data.dsize);
217  free (return_data.dptr);
218  data = to_uni(data);  // convert to unicode
219
220  return true;
221}
222
223
224// returns array of keys
225text_tarray gdbmclass::getkeys ()
226{
227  text_tarray keys;
228
229  text_t key = getfirstkey();
230  while (!key.empty())
231  {
232    keys.push_back(key);
233    key = getnextkey(key);
234  }
235
236  return keys;
237}
238
239
240// returns true on success
241bool gdbmclass::setkeydata (const text_t &key, const text_t &data)
242{
243  if (gdbmfile == NULL) return false;
244 
245  // store the value
246  datum key_data;
247  datum data_data;
248
249  // get a utf-8 encoded c string of the unicode key
250  key_data.dptr = (to_utf8(key)).getcstr();
251  if (key_data.dptr == NULL) {
252    if (logout != NULL) (*logout) << "gdbmclass: out of memory" << endl;
253    return false;
254  }
255  key_data.dsize = strlen (key_data.dptr);
256
257  data_data.dptr = (to_utf8(data)).getcstr();
258  if (data_data.dptr == NULL) {
259    if (logout != NULL) (*logout) << "gdbmclass: out of memory" << endl;
260    delete []key_data.dptr;
261    return false;
262  }
263  data_data.dsize = strlen (data_data.dptr);
264
265  int ret = gdbm_store (gdbmfile, key_data, data_data, GDBM_REPLACE);
266  delete []key_data.dptr;
267  delete []data_data.dptr;
268
269  return (ret == 0);
270}
271
272
273// ----------------------------------------------------------------------------------------
274//   GDBM-ONLY FUNCTIONS
275// ----------------------------------------------------------------------------------------
276
277// getfirstkey and getnextkey are used for traversing the database
278// no insertions or deletions should be carried out while traversing
279// the database. when there are no keys left to visit in the database
280// an empty string is returned.
281text_t gdbmclass::getfirstkey ()
282{
283  if (gdbmfile == NULL) return g_EmptyText;
284
285  // get the first key
286  datum firstkey_data = gdbm_firstkey (gdbmfile);
287  if (firstkey_data.dptr == NULL) return g_EmptyText;
288
289  // convert it to text_t
290  text_t firstkey;
291  firstkey.setcarr (firstkey_data.dptr, firstkey_data.dsize);
292  free (firstkey_data.dptr);
293  return to_uni(firstkey);  // convert to unicode
294}
295
296
297text_t gdbmclass::getnextkey (const text_t &key)
298{
299  if (gdbmfile == NULL || key.empty()) return g_EmptyText;
300
301  // get a utf-8 encoded c string of the unicode key
302  datum key_data;
303  key_data.dptr = (to_utf8(key)).getcstr();
304  if (key_data.dptr == NULL) return g_EmptyText;
305  key_data.dsize = strlen (key_data.dptr);
306 
307  // get the next key
308  datum nextkey_data = gdbm_nextkey (gdbmfile, key_data);
309  if (nextkey_data.dptr == NULL) {
310    delete []key_data.dptr;
311    return g_EmptyText;
312  }
313
314  // convert it to text_t
315  text_t nextkey;
316  nextkey.setcarr (nextkey_data.dptr, nextkey_data.dsize);
317  free (nextkey_data.dptr);
318  delete []key_data.dptr;
319  return to_uni(nextkey);  // convert to unicode
320}
Note: See TracBrowser for help on using the browser.