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

Last change on this file since 1149 was 1149, checked in by sjboddie, 24 years ago

modifications for windows port of GCC

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