Index: /gsdl/trunk/lib/Makefile.in
===================================================================
--- /gsdl/trunk/lib/Makefile.in	(revision 15428)
+++ /gsdl/trunk/lib/Makefile.in	(revision 15429)
@@ -90,19 +90,19 @@
 HEADERS = \
   cfgread.h        cnfgable.h       cnfgator.h       display.h \
-  fileutil.h       gsdlsitecfg.h    gsdltimes.h      gsdltools.h \
-  gsdlunicode.h    infodbclass.h    md5.h            OIDtools.h \
-  phrases.h        text_t.h         $(CORBAHEADERS)  gsdlconf.h
+  fileutil.h       gdbmclass.h      gsdlsitecfg.h    gsdltimes.h \
+  gsdltools.h      gsdlunicode.h    infodbclass.h    md5.h \
+  OIDtools.h       phrases.h        text_t.h         $(CORBAHEADERS)  gsdlconf.h
 
 SOURCES = \
   cfgread.cpp      cnfgable.cpp     cnfgator.cpp     display.cpp \
-  fileutil.cpp     gsdlsitecfg.cpp  gsdltimes.cpp    gsdltools.cpp \
-  gsdlunicode.cpp  infodbclass.cpp  md5.cpp          OIDtools.cpp \
-  phrases.cpp      text_t.cpp       $(CORBASOURCES)
+  fileutil.cpp     gdbmclass.cpp    gsdlsitecfg.cpp  gsdltimes.cpp \
+  gsdltools.cpp    gsdlunicode.cpp  infodbclass.cpp  md5.cpp \
+  OIDtools.cpp     phrases.cpp      text_t.cpp       $(CORBASOURCES)
 
 OBJECTS = \
   cfgread.o        cnfgable.o       cnfgator.o       display.o \
-  fileutil.o       gsdlsitecfg.o    gsdltimes.o      gsdltools.o \
-  gsdlunicode.o    infodbclass.o    md5.o            OIDtools.o \
-  phrases.o        text_t.o         $(CORBAOBJECTS)
+  fileutil.o       gdbmclass.o      gsdlsitecfg.o    gsdltimes.o \
+  gsdltools.o      gsdlunicode.o    infodbclass.o    md5.o \
+  OIDtools.o       phrases.o        text_t.o         $(CORBAOBJECTS)
 
 
Index: /gsdl/trunk/lib/gdbmclass.cpp
===================================================================
--- /gsdl/trunk/lib/gdbmclass.cpp	(revision 15429)
+++ /gsdl/trunk/lib/gdbmclass.cpp	(revision 15429)
@@ -0,0 +1,514 @@
+/**********************************************************************
+ *
+ * gdbmclass.cpp -- 
+ * Copyright (C) 1999-2008  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "gdbmclass.h"
+#include "unitool.h"
+#include "gsdlunicode.h"
+#include "OIDtools.h"
+
+
+gdbmclass::~gdbmclass()
+{
+  closedatabase();
+}
+
+// returns true if opened
+bool gdbmclass::opendatabase (const text_t &filename, int mode, int num_retrys, 
+#ifdef __WIN32__
+			      bool need_filelock
+#else
+                              bool
+#endif
+			      )
+{
+  text_t data_location;
+  int block_size = 512;
+  
+  if (gdbmfile != NULL) {
+    if (openfile == filename) return true;
+    else closedatabase ();
+  }
+
+  openfile = filename;
+  
+  char *namebuffer = filename.getcstr();
+  do {
+#ifdef __WIN32__
+    gdbmfile = gdbm_open (namebuffer, block_size, mode, 00664, NULL, (need_filelock) ? 1 : 0);
+#else
+    gdbmfile = gdbm_open (namebuffer, block_size, mode, 00664, NULL);
+#endif
+    --num_retrys;
+  } while (num_retrys>0 && gdbmfile==NULL &&
+	   (gdbm_errno==GDBM_CANT_BE_READER || gdbm_errno==GDBM_CANT_BE_WRITER));
+  delete []namebuffer;
+  
+  if (gdbmfile == NULL && logout != NULL) {
+    outconvertclass text_t2ascii;
+    (*logout) << text_t2ascii << "database open failed on: " << filename << "\n";
+  }
+
+  return (gdbmfile != NULL);
+}
+
+
+void gdbmclass::closedatabase ()
+{
+  if (gdbmfile == NULL) return;
+  
+  gdbm_close (gdbmfile);
+  gdbmfile = NULL;
+  openfile.clear();
+}
+
+
+// returns true on success
+bool gdbmclass::setinfo (const text_t &key, const infodbclass &info)
+{
+  if (gdbmfile == NULL) return false;
+
+  text_t subkey;
+  text_t data;
+
+  // get all the keys and values
+  infodbclass::const_iterator info_here = info.begin();
+  infodbclass::const_iterator info_end = info.end();
+  while (info_here != info_end) {
+    // add the key
+    subkey.clear();
+    subkey.push_back('<');
+    text_t::const_iterator subkey_here = (*info_here).first.begin();
+    text_t::const_iterator subkey_end = (*info_here).first.end();
+    while (subkey_here != subkey_end) {
+      if (*subkey_here == '>') {
+	subkey.push_back('\\'); subkey.push_back('>');
+      } else if (*subkey_here == '\n') {
+	subkey.push_back('\\'); subkey.push_back('n');
+      } else if (*subkey_here == '\r') {
+	subkey.push_back('\\'); subkey.push_back('r');
+      } else if (*subkey_here == '\\') {
+	subkey.push_back('\\'); subkey.push_back('\\');
+      } else {
+	subkey.push_back (*subkey_here);
+      }
+      ++subkey_here;
+    }
+    subkey.push_back('>');
+
+    // add the values
+    text_tarray::const_iterator subvalue_here = (*info_here).second.begin();
+    text_tarray::const_iterator subvalue_end = (*info_here).second.end();
+    while (subvalue_here != subvalue_end) {
+      data += subkey;
+      
+      text_t::const_iterator thissubvalue_here = (*subvalue_here).begin();
+      text_t::const_iterator thissubvalue_end = (*subvalue_here).end();
+      while (thissubvalue_here != thissubvalue_end) {
+	if (*thissubvalue_here == '>') {
+	  data.push_back('\\'); data.push_back('>');
+	} else if (*thissubvalue_here == '\n') {
+	  data.push_back('\\'); data.push_back('n');
+	} else if (*thissubvalue_here == '\r') {
+	  data.push_back('\\'); data.push_back('r');
+	} else if (*thissubvalue_here == '\\') {
+	  data.push_back('\\'); data.push_back('\\');
+	} else {
+	  data.push_back (*thissubvalue_here);
+	}
+	
+	++thissubvalue_here;
+      }
+      
+      data.push_back('\n');
+      ++subvalue_here;
+    }
+
+    ++info_here;
+  }
+
+  // store the value
+  datum key_data;
+  datum data_data;
+
+  // get a utf-8 encoded c string of the unicode key
+  key_data.dptr = (to_utf8(key)).getcstr();
+  if (key_data.dptr == NULL) {
+    if (logout != NULL) (*logout) << "gdbmclass: out of memory\n";
+    return false;
+  }
+  key_data.dsize = strlen (key_data.dptr);
+
+  data_data.dptr = (to_utf8(data)).getcstr();
+  if (data_data.dptr == NULL) {
+    if (logout != NULL) (*logout) << "gdbmclass: out of memory\n";
+    delete []key_data.dptr;
+    return false;
+  }
+  data_data.dsize = strlen (data_data.dptr);
+
+  int ret = gdbm_store (gdbmfile, key_data, data_data, GDBM_REPLACE);
+  delete []key_data.dptr;
+  delete []data_data.dptr;
+
+  return (ret == 0);
+}
+
+
+//returns true on success
+bool gdbmclass::setinfo (const text_t &key, const text_t &data)
+{
+  if (gdbmfile == NULL) return false;
+  
+  // store the value
+  datum key_data;
+  datum data_data;
+
+  // get a utf-8 encoded c string of the unicode key
+  key_data.dptr = (to_utf8(key)).getcstr();
+  if (key_data.dptr == NULL) {
+    if (logout != NULL) (*logout) << "gdbmclass: out of memory\n";
+    return false;
+  }
+  key_data.dsize = strlen (key_data.dptr);
+
+  data_data.dptr = (to_utf8(data)).getcstr();
+  if (data_data.dptr == NULL) {
+    if (logout != NULL) (*logout) << "gdbmclass: out of memory\n";
+    delete []key_data.dptr;
+    return false;
+  }
+  data_data.dsize = strlen (data_data.dptr);
+
+  int ret = gdbm_store (gdbmfile, key_data, data_data, GDBM_REPLACE);
+  delete []key_data.dptr;
+  delete []data_data.dptr;
+
+  return (ret == 0);
+}
+
+
+void gdbmclass::deletekey (const text_t &key)
+{
+  if (gdbmfile == NULL) return;
+
+  // get a utf-8 encoded c string of the unicode key
+  datum key_data;
+  key_data.dptr = (to_utf8(key)).getcstr();
+  if (key_data.dptr == NULL) return;
+  key_data.dsize = strlen (key_data.dptr);
+
+  // delete the key
+  gdbm_delete (gdbmfile, key_data);
+
+  // free up the key memory
+  delete []key_data.dptr;
+}
+
+
+// getfirstkey and getnextkey are used for traversing the database
+// no insertions or deletions should be carried out while traversing
+// the database. when there are no keys left to visit in the database
+// an empty string is returned.
+text_t gdbmclass::getfirstkey ()
+{
+  if (gdbmfile == NULL) return g_EmptyText;
+
+  // get the first key
+  datum firstkey_data = gdbm_firstkey (gdbmfile);
+  if (firstkey_data.dptr == NULL) return g_EmptyText;
+
+  // convert it to text_t
+  text_t firstkey;
+  firstkey.setcarr (firstkey_data.dptr, firstkey_data.dsize);
+  free (firstkey_data.dptr);
+  return to_uni(firstkey);  // convert to unicode
+}
+
+
+text_t gdbmclass::getnextkey (const text_t &key)
+{
+  if (gdbmfile == NULL || key.empty()) return g_EmptyText;
+
+  // get a utf-8 encoded c string of the unicode key
+  datum key_data;
+  key_data.dptr = (to_utf8(key)).getcstr();
+  if (key_data.dptr == NULL) return g_EmptyText;
+  key_data.dsize = strlen (key_data.dptr);
+  
+  // get the next key
+  datum nextkey_data = gdbm_nextkey (gdbmfile, key_data);
+  if (nextkey_data.dptr == NULL) {
+    delete []key_data.dptr;
+    return g_EmptyText;
+  }
+
+  // convert it to text_t
+  text_t nextkey;
+  nextkey.setcarr (nextkey_data.dptr, nextkey_data.dsize);
+  free (nextkey_data.dptr);
+  delete []key_data.dptr;
+  return to_uni(nextkey);  // convert to unicode
+}
+
+
+// replaces the .fc, .lc, .pr, .rt, .ns and .ps syntax (first child, 
+// last child, parent, root, next sibling, previous sibling) 
+// it expects child, parent, etc. to exist if syntax has been used
+// so you should test before using
+text_t gdbmclass::translate_OID (const text_t &inOID, infodbclass &info)
+{
+  if (inOID.size() < 4) return inOID;
+  if (findchar (inOID.begin(), inOID.end(), '.') == inOID.end()) return inOID;
+
+  text_t OID = inOID;
+  text_tarray tailarray;
+  text_t tail = substr (OID.end()-3, OID.end());
+  if (tail == ".rt") {
+    get_top (inOID, OID);
+    return OID;
+  }
+  while (tail == ".fc" || tail == ".lc" || tail == ".pr" || 
+	 tail == ".ns" || tail == ".ps") {
+    tailarray.push_back(tail);
+    OID.erase (OID.end()-3, OID.end());
+    tail = substr (OID.end()-3, OID.end());
+    if (tail == ".rt") {
+      get_top (inOID, OID);
+      return OID;
+    }
+  }
+
+  if (tailarray.empty()) return inOID;
+  text_tarray::const_iterator begin = tailarray.begin();
+  text_tarray::const_iterator here = tailarray.end() - 1;
+
+  while (here >= begin) {
+
+    if (*here == ".fc")
+      get_first_child (OID, info);
+    else if (*here == ".lc")
+      get_last_child (OID, info);
+    else if (*here == ".pr")
+      OID = get_parent (OID);
+    else if (*here == ".ns")
+      get_next_sibling (OID, info);
+    else if (*here == ".ps")
+      get_previous_sibling (OID, info);
+    
+    if (here == begin)
+      break;
+    --here;
+  }
+
+  return OID;
+}
+
+
+void gdbmclass::get_first_child (text_t &OID, infodbclass &info)
+{
+  text_t firstchild;
+  if (getinfo (OID, info)) {
+    text_t &contains = info["contains"];
+    if (!contains.empty()) {
+      text_t parent = OID;
+      getdelimitstr (contains.begin(), contains.end(), ';', firstchild);
+      if (firstchild.empty()) OID = contains;
+      else OID = firstchild;
+      if (*(OID.begin()) == '"') translate_parent (OID, parent);
+    }
+  }
+}
+
+
+void gdbmclass::get_last_child (text_t &OID, infodbclass &info)
+{
+  text_tarray children;
+  if (getinfo (OID, info)) {
+    text_t &contains = info["contains"];
+    if (!contains.empty()) {
+      text_t parent = OID;
+      splitchar (contains.begin(), contains.end(), ';', children);
+      OID = children.back();
+      if (*(OID.begin()) == '"') translate_parent (OID, parent);
+    }
+  }
+}
+
+  
+void gdbmclass::get_next_sibling (text_t &OID, infodbclass &info)
+{
+  text_tarray siblings;
+  text_t parent = get_parent (OID);
+	     
+  if (getinfo (parent, info)) {
+    text_t &contains = info["contains"];
+    if (!contains.empty()) {
+      splitchar (contains.begin(), contains.end(), ';', siblings);
+      text_tarray::const_iterator here = siblings.begin();
+      text_tarray::const_iterator end = siblings.end();
+      text_t shrunk_OID = OID;
+      shrink_parent (shrunk_OID);
+      while (here != end) {
+	if (*here == shrunk_OID && (here+1 != end)) {
+	  OID = *(here+1);
+	  if (*(OID.begin()) == '"') translate_parent (OID, parent);
+	  break;
+	}
+	++here;
+      }
+    }
+  }
+}
+
+
+void gdbmclass::get_previous_sibling (text_t &OID, infodbclass &info)
+{
+  text_tarray siblings;
+  text_t parent = get_parent (OID);
+
+  if (getinfo (parent, info)) {
+    text_t &contains = info["contains"];
+    if (!contains.empty()) {
+      splitchar (contains.begin(), contains.end(), ';', siblings);
+      text_tarray::const_iterator here = siblings.begin();
+      text_tarray::const_iterator end = siblings.end();
+      text_t shrunk_OID = OID;
+      shrink_parent (shrunk_OID);
+      while (here != end) {
+	if (*here == shrunk_OID && (here != siblings.begin())) {
+	  OID = *(here-1);
+	  if (*(OID.begin()) == '"') translate_parent (OID, parent);
+	  break;
+	}
+	++here;
+      }
+    }
+  }
+}
+
+
+// returns true on success
+bool gdbmclass::getinfo (const text_t& key, infodbclass &info)
+{
+  text_t data;
+  
+  if (!getkeydata (key, data)) return false;
+  text_t::iterator here = data.begin ();
+  text_t::iterator end = data.end ();
+  
+  text_t ikey, ivalue;
+  info.clear (); // reset info
+  
+  while (getinfoline (here, end, ikey, ivalue)) {
+    info.addinfo (ikey, ivalue);
+  }
+  
+  return true;
+}
+
+
+// returns true if exists
+bool gdbmclass::exists (const text_t& key)
+{
+  text_t data;
+  return getkeydata (key, data);
+}
+
+
+// returns true on success
+bool gdbmclass::getkeydata (const text_t& key, text_t &data)
+{
+  datum key_data;
+  datum return_data;
+
+  if (gdbmfile == NULL) return false;
+  
+  // get a utf-8 encoded c string of the unicode key
+  key_data.dptr = (to_utf8(key)).getcstr();
+  if (key_data.dptr == NULL) {
+    if (logout != NULL) (*logout) << "gdbmclass: out of memory\n";
+    return false;
+  }
+  key_data.dsize = strlen (key_data.dptr);
+  
+  // fetch the result
+  return_data = gdbm_fetch (gdbmfile, key_data);
+  delete []key_data.dptr;
+  
+  if (return_data.dptr == NULL) return false;
+
+  data.setcarr (return_data.dptr, return_data.dsize);
+  free (return_data.dptr);
+  data = to_uni(data);  // convert to unicode
+
+  return true;
+}
+
+
+// returns true on success
+bool gdbmclass::getinfoline (text_t::iterator &here, text_t::iterator end, 
+			     text_t &key, text_t &value)
+{
+  key.clear();
+  value.clear();
+
+  // ignore white space
+  while (here != end && is_unicode_space (*here)) ++here;
+
+  // get the '<'
+  if (here == end || *here != '<') return false;
+  ++here;
+  
+  // get the key
+  while (here != end && *here != '>') {
+    key.push_back(*here);
+    ++here;
+  }
+  
+  // get the '>'
+  if (here == end || *here != '>') return false;
+  ++here;
+  
+  // get the value
+  while (here != end && *here != '\n') {
+    if (*here == '\\') { 
+      // found escape character
+      ++here;
+      if (here != end) {
+	if (*here == 'n') value.push_back ('\n');
+	else if (*here == 'r') value.push_back ('\r');
+	else value.push_back(*here);
+      }
+
+    } else {
+      // a normal character
+      value.push_back(*here);
+    }
+
+    ++here;
+  }
+
+  return true;
+}
Index: /gsdl/trunk/lib/gdbmclass.h
===================================================================
--- /gsdl/trunk/lib/gdbmclass.h	(revision 15429)
+++ /gsdl/trunk/lib/gdbmclass.h	(revision 15429)
@@ -0,0 +1,110 @@
+/**********************************************************************
+ *
+ * gdbmclass.h -- 
+ * Copyright (C) 1999-2008  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef GDBMCLASS_H
+#define GDBMCLASS_H
+
+
+#include "gsdlconf.h"
+#include "text_t.h"
+#include "infodbclass.h"
+
+#ifdef __WIN32__
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+#include "autoconf.h"
+#include "systems.h"
+#include "gdbmconst.h"
+#include "gdbm.h"
+#ifdef __cplusplus
+  }
+#endif
+
+#else
+#include <gdbm.h>
+#endif
+
+
+class gdbmclass
+{
+public:
+  gdbmclass() {gdbmfile = NULL; logout = &cerr;};
+  ~gdbmclass();
+  
+  // returns true if opened
+  bool opendatabase (const text_t &filename, int mode, int num_retrys, 
+		     bool need_filelock);
+  void closedatabase ();
+
+  // replaces the .c, .p, .n, .l syntax (child, parent, next, previous) 
+  // it expects child, parent, etc. to exist if syntax has been used
+  // so you should test before using
+  text_t translate_OID (const text_t &OID, infodbclass &info);
+
+  // returns true on success
+  bool getinfo (const text_t& key, infodbclass &info);
+  void setlogout (ostream *thelogout) {logout = thelogout;}
+
+  // returns true if exists
+  bool exists (const text_t& key);
+
+  // returns true on success
+  bool setinfo (const text_t &key, const infodbclass &info);
+  // returns true on success
+  bool setinfo (const text_t &key, const text_t &data);
+
+  void deletekey (const text_t &key);
+
+  // getfirstkey and getnextkey are used for traversing the database
+  // no insertions or deletions should be carried out while traversing
+  // the database. when there are no keys left to visit in the database
+  // an empty string is returned.
+  text_t getfirstkey ();
+  text_t getnextkey (const text_t &key);
+
+    // returns true on success
+  bool getkeydata (const text_t& key, text_t &data);
+
+protected:
+  text_t openfile;
+  GDBM_FILE gdbmfile;
+  ostream *logout;
+
+  void get_first_child (text_t &OID, infodbclass &info);
+  void get_last_child (text_t &OID, infodbclass &info);
+  void get_next_sibling (text_t &OID, infodbclass &info);
+  void get_previous_sibling (text_t &OID, infodbclass &info);
+
+
+  // returns true on success
+  bool getinfoline (text_t::iterator &here, text_t::iterator end, 
+		   text_t &key, text_t &value);
+};
+
+
+#endif
Index: /gsdl/trunk/lib/infodbclass.cpp
===================================================================
--- /gsdl/trunk/lib/infodbclass.cpp	(revision 15428)
+++ /gsdl/trunk/lib/infodbclass.cpp	(revision 15429)
@@ -25,9 +25,4 @@
 
 #include "infodbclass.h"
-#include "unitool.h"
-#include "gsdlunicode.h"
-#include "fileutil.h"
-#include "OIDtools.h"
-#include <stdlib.h>
 
 
@@ -151,488 +146,2 @@
   return &((*here).second);
 }
-
-
-
-gdbmclass::~gdbmclass()
-{
-  closedatabase();
-}
-
-// returns true if opened
-bool gdbmclass::opendatabase (const text_t &filename, int mode, int num_retrys, 
-#ifdef __WIN32__
-			      bool need_filelock
-#else
-                              bool
-#endif
-			      )
-{
-  text_t data_location;
-  int block_size = 512;
-  
-  if (gdbmfile != NULL) {
-    if (openfile == filename) return true;
-    else closedatabase ();
-  }
-
-  openfile = filename;
-  
-  char *namebuffer = filename.getcstr();
-  do {
-#ifdef __WIN32__
-    gdbmfile = gdbm_open (namebuffer, block_size, mode, 00664, NULL, (need_filelock) ? 1 : 0);
-#else
-    gdbmfile = gdbm_open (namebuffer, block_size, mode, 00664, NULL);
-#endif
-    --num_retrys;
-  } while (num_retrys>0 && gdbmfile==NULL &&
-	   (gdbm_errno==GDBM_CANT_BE_READER || gdbm_errno==GDBM_CANT_BE_WRITER));
-  delete []namebuffer;
-  
-  if (gdbmfile == NULL && logout != NULL) {
-    outconvertclass text_t2ascii;
-    (*logout) << text_t2ascii << "database open failed on: " << filename << "\n";
-  }
-
-  return (gdbmfile != NULL);
-}
-
-
-void gdbmclass::closedatabase ()
-{
-  if (gdbmfile == NULL) return;
-  
-  gdbm_close (gdbmfile);
-  gdbmfile = NULL;
-  openfile.clear();
-}
-
-
-// returns true on success
-bool gdbmclass::setinfo (const text_t &key, const infodbclass &info)
-{
-  if (gdbmfile == NULL) return false;
-
-  text_t subkey;
-  text_t data;
-
-  // get all the keys and values
-  infodbclass::const_iterator info_here = info.begin();
-  infodbclass::const_iterator info_end = info.end();
-  while (info_here != info_end) {
-    // add the key
-    subkey.clear();
-    subkey.push_back('<');
-    text_t::const_iterator subkey_here = (*info_here).first.begin();
-    text_t::const_iterator subkey_end = (*info_here).first.end();
-    while (subkey_here != subkey_end) {
-      if (*subkey_here == '>') {
-	subkey.push_back('\\'); subkey.push_back('>');
-      } else if (*subkey_here == '\n') {
-	subkey.push_back('\\'); subkey.push_back('n');
-      } else if (*subkey_here == '\r') {
-	subkey.push_back('\\'); subkey.push_back('r');
-      } else if (*subkey_here == '\\') {
-	subkey.push_back('\\'); subkey.push_back('\\');
-      } else {
-	subkey.push_back (*subkey_here);
-      }
-      ++subkey_here;
-    }
-    subkey.push_back('>');
-
-    // add the values
-    text_tarray::const_iterator subvalue_here = (*info_here).second.begin();
-    text_tarray::const_iterator subvalue_end = (*info_here).second.end();
-    while (subvalue_here != subvalue_end) {
-      data += subkey;
-      
-      text_t::const_iterator thissubvalue_here = (*subvalue_here).begin();
-      text_t::const_iterator thissubvalue_end = (*subvalue_here).end();
-      while (thissubvalue_here != thissubvalue_end) {
-	if (*thissubvalue_here == '>') {
-	  data.push_back('\\'); data.push_back('>');
-	} else if (*thissubvalue_here == '\n') {
-	  data.push_back('\\'); data.push_back('n');
-	} else if (*thissubvalue_here == '\r') {
-	  data.push_back('\\'); data.push_back('r');
-	} else if (*thissubvalue_here == '\\') {
-	  data.push_back('\\'); data.push_back('\\');
-	} else {
-	  data.push_back (*thissubvalue_here);
-	}
-	
-	++thissubvalue_here;
-      }
-      
-      data.push_back('\n');
-      ++subvalue_here;
-    }
-
-    ++info_here;
-  }
-
-  // store the value
-  datum key_data;
-  datum data_data;
-
-  // get a utf-8 encoded c string of the unicode key
-  key_data.dptr = (to_utf8(key)).getcstr();
-  if (key_data.dptr == NULL) {
-    if (logout != NULL) (*logout) << "gdbmclass: out of memory\n";
-    return false;
-  }
-  key_data.dsize = strlen (key_data.dptr);
-
-  data_data.dptr = (to_utf8(data)).getcstr();
-  if (data_data.dptr == NULL) {
-    if (logout != NULL) (*logout) << "gdbmclass: out of memory\n";
-    delete []key_data.dptr;
-    return false;
-  }
-  data_data.dsize = strlen (data_data.dptr);
-
-  int ret = gdbm_store (gdbmfile, key_data, data_data, GDBM_REPLACE);
-  delete []key_data.dptr;
-  delete []data_data.dptr;
-
-  return (ret == 0);
-}
-
-
-//returns true on success
-bool gdbmclass::setinfo (const text_t &key, const text_t &data)
-{
-  if (gdbmfile == NULL) return false;
-  
-  // store the value
-  datum key_data;
-  datum data_data;
-
-  // get a utf-8 encoded c string of the unicode key
-  key_data.dptr = (to_utf8(key)).getcstr();
-  if (key_data.dptr == NULL) {
-    if (logout != NULL) (*logout) << "gdbmclass: out of memory\n";
-    return false;
-  }
-  key_data.dsize = strlen (key_data.dptr);
-
-  data_data.dptr = (to_utf8(data)).getcstr();
-  if (data_data.dptr == NULL) {
-    if (logout != NULL) (*logout) << "gdbmclass: out of memory\n";
-    delete []key_data.dptr;
-    return false;
-  }
-  data_data.dsize = strlen (data_data.dptr);
-
-  int ret = gdbm_store (gdbmfile, key_data, data_data, GDBM_REPLACE);
-  delete []key_data.dptr;
-  delete []data_data.dptr;
-
-  return (ret == 0);
-}
-
-
-void gdbmclass::deletekey (const text_t &key)
-{
-  if (gdbmfile == NULL) return;
-
-  // get a utf-8 encoded c string of the unicode key
-  datum key_data;
-  key_data.dptr = (to_utf8(key)).getcstr();
-  if (key_data.dptr == NULL) return;
-  key_data.dsize = strlen (key_data.dptr);
-
-  // delete the key
-  gdbm_delete (gdbmfile, key_data);
-
-  // free up the key memory
-  delete []key_data.dptr;
-}
-
-
-// getfirstkey and getnextkey are used for traversing the database
-// no insertions or deletions should be carried out while traversing
-// the database. when there are no keys left to visit in the database
-// an empty string is returned.
-text_t gdbmclass::getfirstkey ()
-{
-  if (gdbmfile == NULL) return g_EmptyText;
-
-  // get the first key
-  datum firstkey_data = gdbm_firstkey (gdbmfile);
-  if (firstkey_data.dptr == NULL) return g_EmptyText;
-
-  // convert it to text_t
-  text_t firstkey;
-  firstkey.setcarr (firstkey_data.dptr, firstkey_data.dsize);
-  free (firstkey_data.dptr);
-  return to_uni(firstkey);  // convert to unicode
-}
-
-
-text_t gdbmclass::getnextkey (const text_t &key)
-{
-  if (gdbmfile == NULL || key.empty()) return g_EmptyText;
-
-  // get a utf-8 encoded c string of the unicode key
-  datum key_data;
-  key_data.dptr = (to_utf8(key)).getcstr();
-  if (key_data.dptr == NULL) return g_EmptyText;
-  key_data.dsize = strlen (key_data.dptr);
-  
-  // get the next key
-  datum nextkey_data = gdbm_nextkey (gdbmfile, key_data);
-  if (nextkey_data.dptr == NULL) {
-    delete []key_data.dptr;
-    return g_EmptyText;
-  }
-
-  // convert it to text_t
-  text_t nextkey;
-  nextkey.setcarr (nextkey_data.dptr, nextkey_data.dsize);
-  free (nextkey_data.dptr);
-  delete []key_data.dptr;
-  return to_uni(nextkey);  // convert to unicode
-}
-
-
-// replaces the .fc, .lc, .pr, .rt, .ns and .ps syntax (first child, 
-// last child, parent, root, next sibling, previous sibling) 
-// it expects child, parent, etc. to exist if syntax has been used
-// so you should test before using
-text_t gdbmclass::translate_OID (const text_t &inOID, infodbclass &info)
-{
-  if (inOID.size() < 4) return inOID;
-  if (findchar (inOID.begin(), inOID.end(), '.') == inOID.end()) return inOID;
-
-  text_t OID = inOID;
-  text_tarray tailarray;
-  text_t tail = substr (OID.end()-3, OID.end());
-  if (tail == ".rt") {
-    get_top (inOID, OID);
-    return OID;
-  }
-  while (tail == ".fc" || tail == ".lc" || tail == ".pr" || 
-	 tail == ".ns" || tail == ".ps") {
-    tailarray.push_back(tail);
-    OID.erase (OID.end()-3, OID.end());
-    tail = substr (OID.end()-3, OID.end());
-    if (tail == ".rt") {
-      get_top (inOID, OID);
-      return OID;
-    }
-  }
-
-  if (tailarray.empty()) return inOID;
-  text_tarray::const_iterator begin = tailarray.begin();
-  text_tarray::const_iterator here = tailarray.end() - 1;
-
-  while (here >= begin) {
-
-    if (*here == ".fc")
-      get_first_child (OID, info);
-    else if (*here == ".lc")
-      get_last_child (OID, info);
-    else if (*here == ".pr")
-      OID = get_parent (OID);
-    else if (*here == ".ns")
-      get_next_sibling (OID, info);
-    else if (*here == ".ps")
-      get_previous_sibling (OID, info);
-    
-    if (here == begin)
-      break;
-    --here;
-  }
-
-  return OID;
-}
-
-
-void gdbmclass::get_first_child (text_t &OID, infodbclass &info)
-{
-  text_t firstchild;
-  if (getinfo (OID, info)) {
-    text_t &contains = info["contains"];
-    if (!contains.empty()) {
-      text_t parent = OID;
-      getdelimitstr (contains.begin(), contains.end(), ';', firstchild);
-      if (firstchild.empty()) OID = contains;
-      else OID = firstchild;
-      if (*(OID.begin()) == '"') translate_parent (OID, parent);
-    }
-  }
-}
-
-
-void gdbmclass::get_last_child (text_t &OID, infodbclass &info)
-{
-  text_tarray children;
-  if (getinfo (OID, info)) {
-    text_t &contains = info["contains"];
-    if (!contains.empty()) {
-      text_t parent = OID;
-      splitchar (contains.begin(), contains.end(), ';', children);
-      OID = children.back();
-      if (*(OID.begin()) == '"') translate_parent (OID, parent);
-    }
-  }
-}
-
-  
-void gdbmclass::get_next_sibling (text_t &OID, infodbclass &info)
-{
-  text_tarray siblings;
-  text_t parent = get_parent (OID);
-	     
-  if (getinfo (parent, info)) {
-    text_t &contains = info["contains"];
-    if (!contains.empty()) {
-      splitchar (contains.begin(), contains.end(), ';', siblings);
-      text_tarray::const_iterator here = siblings.begin();
-      text_tarray::const_iterator end = siblings.end();
-      text_t shrunk_OID = OID;
-      shrink_parent (shrunk_OID);
-      while (here != end) {
-	if (*here == shrunk_OID && (here+1 != end)) {
-	  OID = *(here+1);
-	  if (*(OID.begin()) == '"') translate_parent (OID, parent);
-	  break;
-	}
-	++here;
-      }
-    }
-  }
-}
-
-
-void gdbmclass::get_previous_sibling (text_t &OID, infodbclass &info)
-{
-  text_tarray siblings;
-  text_t parent = get_parent (OID);
-
-  if (getinfo (parent, info)) {
-    text_t &contains = info["contains"];
-    if (!contains.empty()) {
-      splitchar (contains.begin(), contains.end(), ';', siblings);
-      text_tarray::const_iterator here = siblings.begin();
-      text_tarray::const_iterator end = siblings.end();
-      text_t shrunk_OID = OID;
-      shrink_parent (shrunk_OID);
-      while (here != end) {
-	if (*here == shrunk_OID && (here != siblings.begin())) {
-	  OID = *(here-1);
-	  if (*(OID.begin()) == '"') translate_parent (OID, parent);
-	  break;
-	}
-	++here;
-      }
-    }
-  }
-}
-
-
-// returns true on success
-bool gdbmclass::getinfo (const text_t& key, infodbclass &info)
-{
-  text_t data;
-  
-  if (!getkeydata (key, data)) return false;
-  text_t::iterator here = data.begin ();
-  text_t::iterator end = data.end ();
-  
-  text_t ikey, ivalue;
-  info.clear (); // reset info
-  
-  while (getinfoline (here, end, ikey, ivalue)) {
-    info.addinfo (ikey, ivalue);
-  }
-  
-  return true;
-}
-
-
-// returns true if exists
-bool gdbmclass::exists (const text_t& key)
-{
-  text_t data;
-  return getkeydata (key, data);
-}
-
-
-// returns true on success
-bool gdbmclass::getkeydata (const text_t& key, text_t &data)
-{
-  datum key_data;
-  datum return_data;
-
-  if (gdbmfile == NULL) return false;
-  
-  // get a utf-8 encoded c string of the unicode key
-  key_data.dptr = (to_utf8(key)).getcstr();
-  if (key_data.dptr == NULL) {
-    if (logout != NULL) (*logout) << "gdbmclass: out of memory\n";
-    return false;
-  }
-  key_data.dsize = strlen (key_data.dptr);
-  
-  // fetch the result
-  return_data = gdbm_fetch (gdbmfile, key_data);
-  delete []key_data.dptr;
-  
-  if (return_data.dptr == NULL) return false;
-
-  data.setcarr (return_data.dptr, return_data.dsize);
-  free (return_data.dptr);
-  data = to_uni(data);  // convert to unicode
-
-  return true;
-}
-
-
-// returns true on success
-bool gdbmclass::getinfoline (text_t::iterator &here, text_t::iterator end, 
-			     text_t &key, text_t &value)
-{
-  key.clear();
-  value.clear();
-
-  // ignore white space
-  while (here != end && is_unicode_space (*here)) ++here;
-
-  // get the '<'
-  if (here == end || *here != '<') return false;
-  ++here;
-  
-  // get the key
-  while (here != end && *here != '>') {
-    key.push_back(*here);
-    ++here;
-  }
-  
-  // get the '>'
-  if (here == end || *here != '>') return false;
-  ++here;
-  
-  // get the value
-  while (here != end && *here != '\n') {
-    if (*here == '\\') { 
-      // found escape character
-      ++here;
-      if (here != end) {
-	if (*here == 'n') value.push_back ('\n');
-	else if (*here == 'r') value.push_back ('\r');
-	else value.push_back(*here);
-      }
-
-    } else {
-      // a normal character
-      value.push_back(*here);
-    }
-
-    ++here;
-  }
-
-  return true;
-}
Index: /gsdl/trunk/lib/infodbclass.h
===================================================================
--- /gsdl/trunk/lib/infodbclass.h	(revision 15428)
+++ /gsdl/trunk/lib/infodbclass.h	(revision 15429)
@@ -41,21 +41,4 @@
 #  include <iostream>
 #  include <fstream>
-#endif
-
-#ifdef __WIN32__
-
-#ifdef __cplusplus
-  extern "C" {
-#endif
-#include "autoconf.h"
-#include "systems.h"
-#include "gdbmconst.h"
-#include "gdbm.h"
-#ifdef __cplusplus
-  }
-#endif
-
-#else
-#include <gdbm.h>
 #endif
 
@@ -138,59 +121,3 @@
 
 
-class gdbmclass {
-public:
-  gdbmclass() {gdbmfile = NULL; logout = &cerr;};
-  ~gdbmclass();
-  
-  // returns true if opened
-  bool opendatabase (const text_t &filename, int mode, int num_retrys, 
-		     bool need_filelock);
-  void closedatabase ();
-
-  // replaces the .c, .p, .n, .l syntax (child, parent, next, previous) 
-  // it expects child, parent, etc. to exist if syntax has been used
-  // so you should test before using
-  text_t translate_OID (const text_t &OID, infodbclass &info);
-
-  // returns true on success
-  bool getinfo (const text_t& key, infodbclass &info);
-  void setlogout (ostream *thelogout) {logout = thelogout;}
-
-  // returns true if exists
-  bool exists (const text_t& key);
-
-  // returns true on success
-  bool setinfo (const text_t &key, const infodbclass &info);
-  // returns true on success
-  bool setinfo (const text_t &key, const text_t &data);
-
-  void deletekey (const text_t &key);
-
-  // getfirstkey and getnextkey are used for traversing the database
-  // no insertions or deletions should be carried out while traversing
-  // the database. when there are no keys left to visit in the database
-  // an empty string is returned.
-  text_t getfirstkey ();
-  text_t getnextkey (const text_t &key);
-
-    // returns true on success
-  bool getkeydata (const text_t& key, text_t &data);
-
-protected:
-  text_t openfile;
-  GDBM_FILE gdbmfile;
-  ostream *logout;
-
-  void get_first_child (text_t &OID, infodbclass &info);
-  void get_last_child (text_t &OID, infodbclass &info);
-  void get_next_sibling (text_t &OID, infodbclass &info);
-  void get_previous_sibling (text_t &OID, infodbclass &info);
-
-
-  // returns true on success
-  bool getinfoline (text_t::iterator &here, text_t::iterator end, 
-		   text_t &key, text_t &value);
-};
-
-
 #endif
Index: /gsdl/trunk/lib/win32.mak
===================================================================
--- /gsdl/trunk/lib/win32.mak	(revision 15428)
+++ /gsdl/trunk/lib/win32.mak	(revision 15429)
@@ -73,19 +73,20 @@
 HEADERS = \
   cfgread.h        cnfgable.h       cnfgator.h       display.h \
-  fileutil.h       gsdlsitecfg.h    gsdltimes.h      gsdltools.h \
-  gsdlunicode.h    infodbclass.h    md5.h            OIDtools.h \
-  phrases.h        text_t.h         gsdlconf.h
+  fileutil.h       gdbmclass.h      gsdlsitecfg.h    gsdltimes.h \
+  gsdltools.h      gsdlunicode.h    infodbclass.h    md5.h \
+  OIDtools.h       phrases.h        text_t.h         gsdlconf.h
 
 SOURCES = \
   cfgread.cpp      cnfgable.cpp     cnfgator.cpp     display.cpp \
-  fileutil.cpp     gsdlsitecfg.cpp  gsdltimes.cpp    gsdltools.cpp \
-  gsdlunicode.cpp  infodbclass.cpp  md5.cpp          OIDtools.cpp \
-  phrases.cpp      text_t.cpp
+  fileutil.cpp     gdbmclass.cpp    gsdlsitecfg.cpp  gsdltimes.cpp \
+  gsdltools.cpp    gsdlunicode.cpp  infodbclass.cpp  md5.cpp \
+  OIDtools.cpp     phrases.cpp      text_t.cpp
 
 OBJECTS = \
   cfgread.o        cnfgable.o       cnfgator.o       display.o \
-  fileutil.o       gsdlsitecfg.o    gsdltimes.o      gsdltools.o \
-  gsdlunicode.o    infodbclass.o    md5.o            OIDtools.o \
-  phrases.o        text_t.o
+  fileutil.o       gdbmclass.o      gsdlsitecfg.o    gsdltimes.o \
+  gsdltools.o      gsdlunicode.o    infodbclass.o    md5.o \
+  OIDtools.o       phrases.o        text_t.o
+
 
 all: gsdllib.lib
