--- dlf.c.orig	Sat Apr 24 11:54:10 1999
+++ dlf.c	Tue May 29 07:47:25 2001
@@ -22,6 +22,10 @@
  *  You should have received a copy of the GNU Library General Public
  *  License along with this library; if not, write to the Free
  *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Changes:
+ * 2001-05-10, Michael Marxmeier (mike@marxmeier.com)
+ *   Fixed HP-UX dlclose() incompatibility
  */
 
 #include <dlf.h>
@@ -47,12 +51,106 @@
 
 #include <dl.h>
 
-static char sccsid[] = "@(#)dynamic load interface -- HP/UX dl(shl)";
+static char sccsid[] = "@(#)dynamic load interface -- HP-UX dl(shl)";
+
+/* 
+Note that HP-UX has a nasty surprise. While shl_load() will add
+shared library instances and return the same handle for all
+mmapped instances of the same library it is not possible to get 
+rid of a single instance. shl_unload() does unload all instances. 
+This is different behaviour to dlclose() which maintains a 
+reference count. 
+
+Pick yor poison:
+
+1. Simply omit the shl_unload(). dld.sl should not suffer but simply 
+   keep increasing its reference count until the program terminates.
+   If you load different drivers in the lifetime of the apapplication
+   the mappings are not freed.
+   
+2. Use the shl_add/del_ref functions to maintain dlopen()/dlclose()
+   compatible reference counting. 
+*/
+
+#define SHL_NO_UNLOAD 1
+#define SHL_REFCNT 0
+
+#if SHL_REFCNT
+
+struct shl_instance {
+  struct shl_instance *next;
+  shl_t hdl;
+  int refcnt;
+};
+
+static struct shl_instance *shl_root_ptr;
+
+static int shl_add_ref(shl_t hdl)
+{
+   struct shl_instance *p = shl_root_ptr;
+   while(p) {
+      if(p->hdl == hdl)
+         break;
+      p = p->next;
+   }
+   if(p)
+      return ++p->refcnt;
+
+   p = malloc(sizeof(struct shl_instance));
+   if(!p) 
+      return -1;
+
+   p->hdl = hdl;
+   p->refcnt = 1;
+   p->next = shl_root_ptr;
+   shl_root_ptr = p;
+   return p->refcnt;
+}
+
+static int shl_del_ref(shl_t hdl)
+{
+   struct shl_instance *p = shl_root_ptr, *pprev = NULL;
+   while(p) {
+      if(p->hdl == hdl)
+         break;
+      pprev = p;
+      p = p->next;
+   }
+   if(!p || !p->refcnt) {
+      errno = EINVAL;
+      return -1;
+   }
+
+   if(--p->refcnt > 0)
+      return p->refcnt;
+
+   if(!pprev)
+      shl_root_ptr = p->next;
+   else
+      pprev->next = p->next;         
+   free(p);
+   return 0;
+}
+
+#endif /* SHL_REFCNT */
 
 void *
 dlopen (char *path, int mode)
 {
-  return (void *) shl_load ((char *) (path), BIND_DEFERRED, 0L);
+   shl_t hdll;
+
+#if SHL_REFCNT
+   int refcnt;
+#endif
+
+   hdll = shl_load(path, BIND_DEFERRED, 0L);
+#if SHL_REFCNT
+   if((refcnt = shl_add_ref(hdll)) == -1) {
+      shl_unload(hdll);
+      hdll = 0;
+   }
+#endif
+   return (void *)hdll;
 }
 
 
@@ -62,8 +160,13 @@
   void *symaddr = 0;
   int ret;
 
+#if unused
+ /*
+  *  iODBC does not need a handle to itself
+  */
   if (!hdll)
     hdll = (void *) PROG_HANDLE;
+#endif
 
   /* Remember, a driver may export calls as function pointers 
    * (i.e. with type TYPE_DATA) rather than as functions 
@@ -71,7 +174,6 @@
    * uses TYPE_UNDEFINED to cover all of them. 
    */
   ret = shl_findsym ((shl_t *) & hdll, sym, TYPE_UNDEFINED, &symaddr);
-
   if (ret == -1)
     return 0;
 
@@ -91,9 +193,20 @@
 int 
 dlclose (void *hdll)
 {
-  return shl_unload ((shl_t) hdll);
+#if SHL_REFCNT
+   int refcnt = shl_del_ref((shl_t)hdll);
+   if(refcnt > 0)
+     return 0;
+#endif     
+
+#if SHL_NO_UNLOAD
+   return 0;
+#else
+   return shl_unload((shl_t)hdll);
+#endif
 }
-#endif /* end of HP/UX Seection */
+
+#endif /* end of HP-UX Section */
 
 
 /*********************************
