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

Last change on this file since 760 was 722, checked in by davidb, 25 years ago

Collection building support through web pages
and internal and external link handling for collection documents

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