source: branches/New_Config_Format-branch/gsdl/src/recpt/infodbclass.cpp@ 1279

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

merged changes to trunk into New_Config_Format branch

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