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

Last change on this file since 411 was 375, checked in by rjmcnab, 25 years ago

Added functionality to modify a gdbm database.

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