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

Last change on this file since 9620 was 9620, checked in by kjdon, 19 years ago

added some x++ -> ++x changes submitted by Emanuel Dejanu

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