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

Last change on this file since 17757 was 17757, checked in by ak19, 15 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?).

File size: 8.4 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 "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 repository browser.