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

Last change on this file since 17988 was 17988, checked in by max, 15 years ago

String manipulation fix. Off by one error.

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