source: trunk/gsdl/src/recpt/infodbclass.cpp@ 533

Last change on this file since 533 was 533, checked in by sjboddie, 25 years ago

added GPL notice

  • Property svn:keywords set to Author Date Id Revision
File size: 14.0 KB
Line 
1/**********************************************************************
2 *
3 * infodbclass.cpp --
4 * Copyright (C) 1999 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 * $Id: infodbclass.cpp 533 1999-09-07 04:57:01Z sjboddie $
25 *
26 *********************************************************************/
27
28/*
29 $Log$
30 Revision 1.4 1999/09/07 04:56:56 sjboddie
31 added GPL notice
32
33 Revision 1.3 1999/09/02 00:26:10 rjmcnab
34 now there can be multiple values for a single key
35
36 Revision 1.2 1999/07/13 23:24:05 rjmcnab
37 Added functionality to modify a gdbm database.
38
39 Revision 1.1 1999/07/11 08:27:52 rjmcnab
40 Moved from src/colservr and added capability to write out data.
41
42 Revision 1.4 1999/05/10 03:43:48 sjboddie
43 lots of changes to lots of files - getting document action going
44
45 Revision 1.3 1999/04/30 02:00:46 sjboddie
46 lots of stuff to do with getting documentaction working
47
48 Revision 1.2 1999/04/06 22:20:31 rjmcnab
49 Got browsefilter working.
50
51 Revision 1.1 1999/03/30 05:10:07 rjmcnab
52 Initial revision.
53
54 */
55
56
57#include "infodbclass.h"
58#include "unitool.h"
59#include "gsdlunicode.h"
60#include "fileutil.h"
61#include "OIDtools.h"
62#include <stdlib.h>
63
64
65
66
67// constructors
68infodbclass::infodbclass () {
69}
70
71void infodbclass::setinfo (const text_t &key, const text_t &value) {
72 text_tarray &tarr = info[key];
73 tarr.erase(tarr.begin(), tarr.end());
74 tarr.push_back(value);
75}
76
77void infodbclass::setintinfo (const text_t &key, int value) {
78 setinfo (key, value);
79}
80
81void infodbclass::setcinfo (const text_t &key, unsigned short c) {
82 text_t t;
83 t.push_back (c);
84 setinfo (key, t);
85}
86
87text_t *infodbclass::getinfo (const text_t &key) {
88 iterator here = info.find (key);
89 if (here == info.end()) return NULL;
90
91 if ((*here).second.empty()) return NULL;
92
93 return &((*here).second[0]);
94}
95
96int infodbclass::getintinfo (const text_t &key) {
97 text_t *t = getinfo (key);
98 if (t == NULL) return 0;
99 return t->getint();
100}
101
102text_t &infodbclass::operator[] (const text_t &key) {
103 text_tarray &tarr = info[key];
104 if (tarr.empty()) {
105 text_t e;
106 tarr.push_back(e);
107 }
108 return tarr[0];
109}
110
111
112void infodbclass::addinfo (const text_t &key, const text_t &value) {
113 text_tarray &tarr = info[key];
114 tarr.push_back (value);
115}
116
117void infodbclass::addintinfo (const text_t &key, int value) {
118 addinfo (key, value);
119}
120
121void infodbclass::addcinfo (const text_t &key, unsigned short c) {
122 text_t t;
123 t.push_back(c);
124 addinfo (key, t);
125}
126
127text_tarray *infodbclass::getmultinfo (const text_t &key) {
128 iterator here = info.find (key);
129 if (here == info.end()) return NULL;
130
131 return &((*here).second);
132}
133
134
135
136
137// returns true if opened
138bool gdbmclass::opendatabase (const text_t &filename, int mode, int num_retrys,
139 bool need_filelock) {
140 text_t data_location;
141 int block_size = 512;
142
143 if (gdbmfile != NULL) {
144 if (openfile == filename) return true;
145 else closedatabase ();
146 }
147
148 openfile = filename;
149
150 char *namebuffer = filename.getcstr();
151 do {
152#ifdef __WIN32__
153 gdbmfile = gdbm_open (namebuffer, block_size, mode, 00664, NULL, (need_filelock) ? 1 : 0);
154#else
155 gdbmfile = gdbm_open (namebuffer, block_size, mode, 00664, NULL);
156#endif
157 num_retrys--;
158 } while (num_retrys>0 && gdbmfile==NULL &&
159 (gdbm_errno==GDBM_CANT_BE_READER || gdbm_errno==GDBM_CANT_BE_WRITER));
160 delete namebuffer;
161
162 if (gdbmfile == NULL && logout != NULL) {
163 outconvertclass text_t2ascii;
164 (*logout) << text_t2ascii << "database open failed on: " << filename << "\n";
165 }
166
167 return (gdbmfile != NULL);
168}
169
170void gdbmclass::closedatabase () {
171 if (gdbmfile == NULL) return;
172
173 gdbm_close (gdbmfile);
174 gdbmfile = NULL;
175 openfile.clear();
176}
177
178
179// returns true on success
180bool gdbmclass::setinfo (const text_t &key, const infodbclass &info) {
181 if (gdbmfile == NULL) return false;
182
183 text_t subkey;
184 text_t data;
185
186 // get all the keys and values
187 infodbclass::const_iterator info_here = info.begin();
188 infodbclass::const_iterator info_end = info.end();
189 while (info_here != info_end) {
190 // add the key
191 subkey.clear();
192 subkey.push_back('<');
193 text_t::const_iterator subkey_here = (*info_here).first.begin();
194 text_t::const_iterator subkey_end = (*info_here).first.end();
195 while (subkey_here != subkey_end) {
196 if (*subkey_here == '>') {
197 subkey.push_back('\\'); subkey.push_back('>');
198 } else if (*subkey_here == '\n') {
199 subkey.push_back('\\'); subkey.push_back('n');
200 } else if (*subkey_here == '\r') {
201 subkey.push_back('\\'); subkey.push_back('r');
202 } else {
203 subkey.push_back (*subkey_here);
204 }
205 subkey_here++;
206 }
207 subkey.push_back('>');
208
209 // add the values
210 text_tarray::const_iterator subvalue_here = (*info_here).second.begin();
211 text_tarray::const_iterator subvalue_end = (*info_here).second.end();
212 while (subvalue_here != subvalue_end) {
213 data += subkey;
214
215 text_t::const_iterator thissubvalue_here = (*subvalue_here).begin();
216 text_t::const_iterator thissubvalue_end = (*subvalue_here).end();
217 while (thissubvalue_here != thissubvalue_end) {
218 if (*thissubvalue_here == '>') {
219 data.push_back('\\'); data.push_back('>');
220 } else if (*thissubvalue_here == '\n') {
221 data.push_back('\\'); data.push_back('n');
222 } else if (*thissubvalue_here == '\r') {
223 data.push_back('\\'); data.push_back('r');
224 } else {
225 data.push_back (*thissubvalue_here);
226 }
227
228 thissubvalue_here++;
229 }
230
231 data.push_back('\n');
232 subvalue_here++;
233 }
234
235 info_here++;
236 }
237
238 // store the value
239 datum key_data;
240 datum data_data;
241
242 // get a utf-8 encoded c string of the unicode key
243 key_data.dptr = (to_utf8(key)).getcstr();
244 if (key_data.dptr == NULL) {
245 if (logout != NULL) (*logout) << "gdbmclass: out of memory\n";
246 return false;
247 }
248 key_data.dsize = strlen (key_data.dptr);
249
250 data_data.dptr = (to_utf8(data)).getcstr();
251 if (data_data.dptr == NULL) {
252 if (logout != NULL) (*logout) << "gdbmclass: out of memory\n";
253 delete key_data.dptr;
254 }
255 data_data.dsize = strlen (data_data.dptr);
256
257 int ret = gdbm_store (gdbmfile, key_data, data_data, GDBM_REPLACE);
258 delete key_data.dptr;
259 delete data_data.dptr;
260
261 return (ret == 0);
262}
263
264
265void gdbmclass::deletekey (const text_t &key) {
266 if (gdbmfile == NULL) return;
267
268 // get a utf-8 encoded c string of the unicode key
269 datum key_data;
270 key_data.dptr = (to_utf8(key)).getcstr();
271 if (key_data.dptr == NULL) return;
272 key_data.dsize = strlen (key_data.dptr);
273
274 // delete the key
275 gdbm_delete (gdbmfile, key_data);
276
277 // free up the key memory
278 delete key_data.dptr;
279}
280
281
282// getfirstkey and getnextkey are used for traversing the database
283// no insertions or deletions should be carried out while traversing
284// the database. when there are no keys left to visit in the database
285// an empty string is returned.
286text_t gdbmclass::getfirstkey () {
287 if (gdbmfile == NULL) return "";
288
289 // get the first key
290 datum firstkey_data = gdbm_firstkey (gdbmfile);
291 if (firstkey_data.dptr == NULL) return "";
292
293 // convert it to text_t
294 text_t firstkey;
295 firstkey.setcarr (firstkey_data.dptr, firstkey_data.dsize);
296 free (firstkey_data.dptr);
297 return to_uni(firstkey); // convert to unicode
298}
299
300text_t gdbmclass::getnextkey (const text_t &key) {
301 if (gdbmfile == NULL || key.empty()) return "";
302
303 // get a utf-8 encoded c string of the unicode key
304 datum key_data;
305 key_data.dptr = (to_utf8(key)).getcstr();
306 if (key_data.dptr == NULL) return "";
307 key_data.dsize = strlen (key_data.dptr);
308
309 // get the next key
310 datum nextkey_data = gdbm_nextkey (gdbmfile, key_data);
311 if (nextkey_data.dptr == NULL) {
312 delete key_data.dptr;
313 return "";
314 }
315
316 // convert it to text_t
317 text_t nextkey;
318 nextkey.setcarr (nextkey_data.dptr, nextkey_data.dsize);
319 free (nextkey_data.dptr);
320 delete key_data.dptr;
321 return to_uni(nextkey); // convert to unicode
322}
323
324
325// replaces the .fc, .lc, .pr, .ns and .ps syntax (first child,
326// last child, parent, next sibling, previous sibling)
327// it expects child, parent, etc. to exist if syntax has been used
328// so you should test before using
329text_t gdbmclass::translate_OID (const text_t &inOID, infodbclass &info) {
330
331 if (inOID.size() < 4) return inOID;
332 if (findchar (inOID.begin(), inOID.end(), '.') == inOID.end()) return inOID;
333
334 text_t OID = inOID;
335 text_tarray tailarray;
336 text_t tail = substr (OID.end()-3, OID.end());
337 while (tail == ".fc" || tail == ".lc" || tail == ".pr" ||
338 tail == ".ns" || tail == ".ps") {
339 tailarray.push_back(tail);
340 OID.erase (OID.end()-3, OID.end());
341 tail = substr (OID.end()-3, OID.end());
342 }
343
344 if (!tailarray.size()) return inOID;
345 text_tarray::const_iterator begin = tailarray.begin();
346 text_tarray::const_iterator here = tailarray.end() - 1;
347
348 while (here >= begin) {
349
350 if (*here == ".fc")
351 get_first_child (OID, info);
352 else if (*here == ".lc")
353 get_last_child (OID, info);
354 else if (*here == ".pr")
355 OID = get_parent (OID);
356 else if (*here == ".ns")
357 get_next_sibling (OID, info);
358 else if (*here == ".ps")
359 get_previous_sibling (OID, info);
360
361 here --;
362 }
363 return OID;
364}
365
366void gdbmclass::get_first_child (text_t &OID, infodbclass &info) {
367
368 text_t firstchild;
369 if (getinfo (OID, info)) {
370 text_t &contains = info["contains"];
371 if (!contains.empty()) {
372 text_t parent = OID;
373 getdelimitstr (contains.begin(), contains.end(), ';', firstchild);
374 if (firstchild.empty()) OID = contains;
375 else OID = firstchild;
376 if (*(OID.begin()) == '"') translate_parent (OID, parent);
377 }
378 }
379}
380
381void gdbmclass::get_last_child (text_t &OID, infodbclass &info) {
382
383 text_tarray children;
384 if (getinfo (OID, info)) {
385 text_t &contains = info["contains"];
386 if (!contains.empty()) {
387 text_t parent = OID;
388 splitchar (contains.begin(), contains.end(), ';', children);
389 OID = children.back();
390 if (*(OID.begin()) == '"') translate_parent (OID, parent);
391 }
392 }
393}
394
395void gdbmclass::get_next_sibling (text_t &OID, infodbclass &info) {
396
397 text_tarray siblings;
398 text_t parent = get_parent (OID);
399
400 if (getinfo (parent, info)) {
401 text_t &contains = info["contains"];
402 if (!contains.empty()) {
403 splitchar (contains.begin(), contains.end(), ';', siblings);
404 text_tarray::const_iterator here = siblings.begin();
405 text_tarray::const_iterator end = siblings.end();
406 text_t shrunk_OID = OID;
407 shrink_parent (shrunk_OID);
408 while (here != end) {
409 if (*here == shrunk_OID && (here+1 != end)) {
410 OID = *(here+1);
411 if (*(OID.begin()) == '"') translate_parent (OID, parent);
412 break;
413 }
414 here ++;
415 }
416 }
417 }
418}
419
420void gdbmclass::get_previous_sibling (text_t &OID, infodbclass &info) {
421
422 text_tarray siblings;
423 text_t parent = get_parent (OID);
424
425 if (getinfo (parent, info)) {
426 text_t &contains = info["contains"];
427 if (!contains.empty()) {
428 splitchar (contains.begin(), contains.end(), ';', siblings);
429 text_tarray::const_iterator here = siblings.begin();
430 text_tarray::const_iterator end = siblings.end();
431 text_t shrunk_OID = OID;
432 shrink_parent (shrunk_OID);
433 while (here != end) {
434 if (*here == shrunk_OID && (here != siblings.begin())) {
435 OID = *(here-1);
436 if (*(OID.begin()) == '"') translate_parent (OID, parent);
437 break;
438 }
439 here ++;
440 }
441 }
442 }
443}
444
445// returns true on success
446bool gdbmclass::getinfo (text_t key, infodbclass &info) {
447 text_t data;
448
449 if (!getkeydata (key, data)) return false;
450 text_t::iterator here = data.begin ();
451 text_t::iterator end = data.end ();
452
453 text_t ikey, ivalue;
454 info.clear (); // reset info
455
456 while (getinfoline (here, end, ikey, ivalue)) {
457 info.addinfo (ikey, ivalue);
458 }
459
460 return true;
461}
462
463// returns true if exists
464bool gdbmclass::exists (text_t key) {
465 text_t data;
466 return getkeydata (key, data);
467}
468
469// returns true on success
470bool gdbmclass::getkeydata (text_t key, text_t &data) {
471 datum key_data;
472 datum return_data;
473
474 if (gdbmfile == NULL) return false;
475
476 // get a utf-8 encoded c string of the unicode key
477 key_data.dptr = (to_utf8(key)).getcstr();
478 if (key_data.dptr == NULL) {
479 if (logout != NULL) (*logout) << "gdbmclass: out of memory\n";
480 return false;
481 }
482 key_data.dsize = strlen (key_data.dptr);
483
484 // fetch the result
485 return_data = gdbm_fetch (gdbmfile, key_data);
486 delete key_data.dptr;
487
488 if (return_data.dptr == NULL) return false;
489
490 data.setcarr (return_data.dptr, return_data.dsize);
491 free (return_data.dptr);
492 data = to_uni(data); // convert to unicode
493
494 return true;
495}
496
497// returns true on success
498bool gdbmclass::getinfoline (text_t::iterator &here, text_t::iterator end,
499 text_t &key, text_t &value) {
500 key.clear();
501 value.clear();
502
503 // ignore white space
504 while (here != end && is_unicode_space (*here)) here++;
505
506 // get the '<'
507 if (here == end || *here != '<') return false;
508 here++;
509
510 // get the key
511 while (here != end && *here != '>') {
512 key.push_back(*here);
513 here++;
514 }
515
516 // get the '>'
517 if (here == end || *here != '>') return false;
518 here++;
519
520 // get the value
521 while (here != end && *here != '\n') {
522 if (*here == '\\') {
523 // found escape character
524 here++;
525 if (here != end) {
526 if (*here == 'n') value.push_back ('\n');
527 else if (*here == 'r') value.push_back ('\r');
528 else value.push_back(*here);
529 }
530
531 } else {
532 // a normal character
533 value.push_back(*here);
534 }
535
536 here++;
537 }
538
539 return true;
540}
541
Note: See TracBrowser for help on using the repository browser.