The xmalloc/xfree functions from YAZ are used to manage memory.
[ir-tcl-moved-to-github.git] / ir-tcl.c
index 8355899..a9742c1 100644 (file)
--- a/ir-tcl.c
+++ b/ir-tcl.c
@@ -5,7 +5,59 @@
  * Sebastian Hammer, Adam Dickmeiss
  *
  * $Log: ir-tcl.c,v $
- * Revision 1.77  1996-02-20 17:52:58  adam
+ * Revision 1.91  1996-07-03 13:31:11  adam
+ * The xmalloc/xfree functions from YAZ are used to manage memory.
+ *
+ * Revision 1.90  1996/06/27  14:21:00  adam
+ * Yet another Windows port.
+ *
+ * Revision 1.89  1996/06/11  15:27:15  adam
+ * Event type set to connect a little earlier in the do_connect function.
+ *
+ * Revision 1.88  1996/06/03  09:04:22  adam
+ * Changed a few logf calls.
+ *
+ * Revision 1.87  1996/05/29  06:37:51  adam
+ * Function ir_tcl_get_grs_r enhanced so that specific elements can be
+ * extracted.
+ *
+ * Revision 1.86  1996/03/20 13:54:04  adam
+ * The Tcl_File structure is only manipulated in the Tk-event interface
+ * in tkinit.c.
+ *
+ * Revision 1.85  1996/03/15  11:15:48  adam
+ * Modified to use new prototypes for p_query_rpn and p_query_scan.
+ *
+ * Revision 1.84  1996/03/07  12:42:49  adam
+ * Better logging when callback is invoked.
+ *
+ * Revision 1.83  1996/03/05  09:21:09  adam
+ * Bug fix: memory used by GRS records wasn't freed.
+ * Rewrote some of the error handling code - the connection is always
+ * closed before failback is called.
+ * If failback is defined the send APDU methods (init, search, ...) will
+ * return OK but invoke failback (as is the case if the write operation
+ * fails).
+ * Bug fix: ref_count in assoc object could grow if fraction of PDU was
+ * read.
+ *
+ * Revision 1.82  1996/02/29  15:30:21  adam
+ * Export of IrTcl functionality to extensions.
+ *
+ * Revision 1.81  1996/02/26  18:38:32  adam
+ * Work on export of set methods.
+ *
+ * Revision 1.80  1996/02/23  17:31:39  adam
+ * More functions made available to the wais tcl extension.
+ *
+ * Revision 1.79  1996/02/23  13:41:38  adam
+ * Work on public access to simple ir class system.
+ *
+ * Revision 1.78  1996/02/21  10:16:08  adam
+ * Simplified select handling. Only one function ir_tcl_select_set has
+ * to be externally defined.
+ *
+ * Revision 1.77  1996/02/20  17:52:58  adam
  * Uses the YAZ oid system to name record syntax object identifiers.
  *
  * Revision 1.76  1996/02/20  16:09:51  adam
 
 #include "ir-tclp.h"
 
-typedef struct {
-    int type;
-    char *name;
-    int (*method) (void *obj, Tcl_Interp *interp, int argc, char **argv);
-} IrTcl_Method;
+static void ir_deleteDiags (IrTcl_Diagnostic **dst_list, int *dst_num);
 
-typedef struct {
-    void *obj;
-    IrTcl_Method *tab;
-} IrTcl_Methods;
+static void ir_select_notify (ClientData clientData, int r, int w, int e);
 
-static void ir_deleteDiags (IrTcl_Diagnostic **dst_list, int *dst_num);
-static int do_disconnect (void *obj, Tcl_Interp *interp, 
-                          int argc, char **argv);
+void ir_select_add (int fd, void *obj)
+{
+    ir_tcl_select_set (ir_select_notify, fd, obj, 1, 0, 0);
+}
+
+void ir_select_add_write (int fd, void *obj)
+{
+    ir_tcl_select_set (ir_select_notify, fd, obj, 1, 1, 0);
+}
+
+void ir_select_remove (int fd, void *obj)
+{
+    ir_tcl_select_set (NULL, fd, obj, 0, 0, 0);
+}
+
+void ir_select_remove_write (int fd, void *obj)
+{
+    ir_tcl_select_set (ir_select_notify, fd, obj, 1, 0, 0);
+}
+
+static void delete_IR_record (IrTcl_RecordList *rl)
+{
+    switch (rl->which)
+    {
+    case Z_NamePlusRecord_databaseRecord:
+        switch (rl->u.dbrec.type)
+        {
+        case VAL_GRS1:
+            ir_tcl_grs_del (&rl->u.dbrec.u.grs1);
+            break;
+        default:
+            break;
+        }
+        xfree (rl->u.dbrec.buf);
+        break;
+    case Z_NamePlusRecord_surrogateDiagnostic:
+        ir_deleteDiags (&rl->u.surrogateDiagnostics.list,
+                        &rl->u.surrogateDiagnostics.num);
+        break;
+    }
+    xfree (rl->elements);
+}
 
 static IrTcl_RecordList *new_IR_record (IrTcl_SetObj *setobj, 
                                         int no, int which, 
@@ -311,18 +395,7 @@ static IrTcl_RecordList *new_IR_record (IrTcl_SetObj *setobj,
         if (no == rl->no && (!rl->elements || !elements ||
                              !strcmp(elements, rl->elements)))
         {
-            free (rl->elements);
-            switch (rl->which)
-            {
-            case Z_NamePlusRecord_databaseRecord:
-                free (rl->u.dbrec.buf);
-                rl->u.dbrec.buf = NULL;
-                break;
-            case Z_NamePlusRecord_surrogateDiagnostic:
-                ir_deleteDiags (&rl->u.surrogateDiagnostics.list,
-                                &rl->u.surrogateDiagnostics.num);
-                break;
-            }
+            delete_IR_record (rl);
             break;
         }
     }
@@ -339,20 +412,23 @@ static IrTcl_RecordList *new_IR_record (IrTcl_SetObj *setobj,
 }
 
 /* 
- * IrTcl_eval
+ * ir_tcl_eval
  */
-int IrTcl_eval (Tcl_Interp *interp, const char *command)
+int ir_tcl_eval (Tcl_Interp *interp, const char *command)
 {
     char *tmp = ir_tcl_malloc (strlen(command)+1);
     int r;
 
+    logf (LOG_DEBUG, "Invoking %.23s ...", command);
     strcpy (tmp, command);
     r = Tcl_Eval (interp, tmp);
     if (r == TCL_ERROR)
+    {
         logf (LOG_WARN, "Tcl error in line %d: %s", interp->errorLine, 
               interp->result);
+    }
     Tcl_FreeResult (interp);
-    free (tmp);
+    xfree (tmp);
     return r;
 }
 
@@ -402,26 +478,17 @@ static void delete_IR_records (IrTcl_SetObj *setobj)
 
     for (rl = setobj->record_list; rl; rl = rl1)
     {
-        switch (rl->which)
-        {
-        case Z_NamePlusRecord_databaseRecord:
-            free (rl->u.dbrec.buf);
-            break;
-        case Z_NamePlusRecord_surrogateDiagnostic:
-            ir_deleteDiags (&rl->u.surrogateDiagnostics.list,
-                            &rl->u.surrogateDiagnostics.num);
-            break;
-        }
+        delete_IR_record (rl);
         rl1 = rl->next;
-        free (rl);
+        xfree (rl);
     }
     setobj->record_list = NULL;
 }
 
 /*
- * get_set_int: Set/get integer value
+ * ir_tcl_get_set_int: Set/get integer value
  */
-static int get_set_int (int *val, Tcl_Interp *interp, int argc, char **argv)
+int ir_tcl_get_set_int (int *val, Tcl_Interp *interp, int argc, char **argv)
 {
     char buf[20];
     
@@ -436,9 +503,10 @@ static int get_set_int (int *val, Tcl_Interp *interp, int argc, char **argv)
 }
 
 /*
- * ir_method: Search for method in table and invoke method handler
+ * ir_tcl_method: Search for method in table and invoke method handler
  */
-int ir_method (Tcl_Interp *interp, int argc, char **argv, IrTcl_Methods *tab)
+int ir_tcl_method (Tcl_Interp *interp, int argc, char **argv,
+                   IrTcl_Methods *tab, int *ret)
 {
     IrTcl_Methods *tab_i = tab;
     IrTcl_Method *t;
@@ -452,45 +520,29 @@ int ir_method (Tcl_Interp *interp, int argc, char **argv, IrTcl_Methods *tab)
             }
             else
                 if (!strcmp (t->name, argv[1]))
-                    return (*t->method)(tab_i->obj, interp, argc, argv);
+                {
+                    *ret = (*t->method)(tab_i->obj, interp, argc, argv);
+                    return TCL_OK;
+                }
 
     if (argc <= 0)
         return TCL_OK;
+#if 0
     Tcl_AppendResult (interp, "Bad method: ", argv[1], 
                       ". Possible methods:", NULL);
     for (tab_i = tab; tab_i->tab; tab_i++)
         for (t = tab_i->tab; t->name; t++)
             Tcl_AppendResult (interp, " ", t->name, NULL);
+#endif
+    *ret = TCL_ERROR;
     return TCL_ERROR;
 }
 
 /*
- * ir_method_r: Get status for all readable elements
+ *  ir_tcl_named_bits: get/set named bits
  */
-int ir_method_r (void *obj, Tcl_Interp *interp, int argc, char **argv,
-                 IrTcl_Method *tab)
-{
-    char *argv_n[3];
-    int argc_n;
-
-    argv_n[0] = argv[0];
-    argc_n = 2;
-    for (; tab->name; tab++)
-        if (tab->type)
-        {
-            argv_n[1] = tab->name;
-            Tcl_AppendResult (interp, "{", NULL);
-            (*tab->method)(obj, interp, argc_n, argv_n);
-            Tcl_AppendResult (interp, "} ", NULL);
-        }
-    return TCL_OK;
-}
-
-/*
- *  ir_named_bits: get/set named bits
- */
-int ir_named_bits (struct ir_named_entry *tab, Odr_bitmask *ob,
-                   Tcl_Interp *interp, int argc, char **argv)
+int ir_tcl_named_bits (struct ir_named_entry *tab, Odr_bitmask *ob,
+                       Tcl_Interp *interp, int argc, char **argv)
 {
     struct ir_named_entry *ti;
     if (argc > 0)
@@ -534,7 +586,7 @@ static void set_referenceId (ODR o, Z_ReferenceId **dst, const char *src)
 
 static void get_referenceId (char **dst, Z_ReferenceId *src)
 {
-    free (*dst);
+    xfree (*dst);
     if (!src)
     {
         *dst = NULL;
@@ -559,6 +611,7 @@ static int do_init_request (void *obj, Tcl_Interp *interp,
 
     if (argc <= 0)
         return TCL_OK;
+    logf (LOG_DEBUG, "init %s", *argv);
     if (!p->cs_link)
     {
         interp->result = "init: not connected";
@@ -683,7 +736,7 @@ static int do_options (void *obj, Tcl_Interp *interp,
         ODR_MASK_SET (&p->options, 14);
         return TCL_OK;
     }
-    return ir_named_bits (options_tab, &p->options, interp, argc-2, argv+2);
+    return ir_tcl_named_bits (options_tab, &p->options, interp, argc-2, argv+2);
 }
 
 /*
@@ -789,7 +842,7 @@ static int do_preferredMessageSize (void *obj, Tcl_Interp *interp,
         p->preferredMessageSize = 30000;
         return TCL_OK;
     }
-    return get_set_int (&p->preferredMessageSize, interp, argc, argv);
+    return ir_tcl_get_set_int (&p->preferredMessageSize, interp, argc, argv);
 }
 
 /*
@@ -805,7 +858,7 @@ static int do_maximumRecordSize (void *obj, Tcl_Interp *interp,
         p->maximumRecordSize = 30000;
         return TCL_OK;
     }
-    return get_set_int (&p->maximumRecordSize, interp, argc, argv);
+    return ir_tcl_get_set_int (&p->maximumRecordSize, interp, argc, argv);
 }
 
 /*
@@ -818,7 +871,7 @@ static int do_initResult (void *obj, Tcl_Interp *interp,
    
     if (argc <= 0)
         return TCL_OK;
-    return get_set_int (&p->initResult, interp, argc, argv);
+    return ir_tcl_get_set_int (&p->initResult, interp, argc, argv);
 }
 
 
@@ -837,7 +890,7 @@ static int do_implementationName (void *obj, Tcl_Interp *interp,
         return ir_tcl_strdel (interp, &p->implementationName);
     if (argc == 3)
     {
-        free (p->implementationName);
+        xfree (p->implementationName);
         if (ir_tcl_strdup (interp, &p->implementationName, argv[2])
             == TCL_ERROR)
             return TCL_ERROR;
@@ -946,10 +999,10 @@ static int do_idAuthentication (void *obj, Tcl_Interp *interp,
 
     if (argc >= 3 || argc == -1)
     {
-        free (p->idAuthenticationOpen);
-        free (p->idAuthenticationGroupId);
-        free (p->idAuthenticationUserId);
-        free (p->idAuthenticationPassword);
+        xfree (p->idAuthenticationOpen);
+        xfree (p->idAuthenticationGroupId);
+        xfree (p->idAuthenticationUserId);
+        xfree (p->idAuthenticationPassword);
     }
     if (argc >= 3 || argc <= 0)
     {
@@ -1010,6 +1063,7 @@ static int do_connect (void *obj, Tcl_Interp *interp,
         return TCL_OK;
     if (argc == 3)
     {
+        logf (LOG_DEBUG, "connect %s %s", *argv, argv[2]);
         if (p->hostname)
         {
             interp->result = "already connected";
@@ -1050,41 +1104,26 @@ static int do_connect (void *obj, Tcl_Interp *interp,
         }
         if (ir_tcl_strdup (interp, &p->hostname, argv[2]) == TCL_ERROR)
             return TCL_ERROR;
-#if IRTCL_GENERIC_FILES
-#ifdef WINDOWS
-        p->csFile = Tcl_GetFile (cs_fileno(p->cs_link), TCL_WIN_SOCKET);
-#else
-        p->csFile = Tcl_GetFile (cs_fileno(p->cs_link), TCL_UNIX_FD);
-#endif
-#endif
+        p->eventType = "connect";
         if ((r=cs_connect (p->cs_link, addr)) < 0)
         {
             interp->result = "connect fail";
-            do_disconnect (p, NULL, 2, NULL);
+            ir_tcl_disconnect (p);
             return TCL_ERROR;
         }
-       logf(LOG_DEBUG, "cs_connect() returned %d fd=%d", r,
-             cs_fileno(p->cs_link));
-        p->eventType = "connect";
-#if IRTCL_GENERIC_FILES
-        ir_select_add (p->csFile, p);
-#else
         ir_select_add (cs_fileno (p->cs_link), p);
-#endif
         if (r == 1)
         {
-#if IRTCL_GENERIC_FILES
-            ir_select_add_write (p->csFile, p);
-#else
+            logf (LOG_DEBUG, "connect pending fd=%d", cs_fileno(p->cs_link));
             ir_select_add_write (cs_fileno (p->cs_link), p);
-#endif
             p->state = IR_TCL_R_Connecting;
         }
         else
         {
+            logf (LOG_DEBUG, "connect ok fd=%d", cs_fileno(p->cs_link));
             p->state = IR_TCL_R_Idle;
             if (p->callback)
-                IrTcl_eval (p->interp, p->callback);
+                ir_tcl_eval (p->interp, p->callback);
         }
     }
     else
@@ -1092,47 +1131,24 @@ static int do_connect (void *obj, Tcl_Interp *interp,
     return TCL_OK;
 }
 
-/*
- * do_disconnect: disconnect method on IR object
+/* 
+ * ir_tcl_disconnect: close connection
  */
-static int do_disconnect (void *obj, Tcl_Interp *interp,
-                          int argc, char **argv)
+void ir_tcl_disconnect (IrTcl_Obj *p)
 {
-    IrTcl_Obj *p = obj;
-
-    if (argc == 0)
-    {
-        p->state = IR_TCL_R_Idle;
-        p->eventType = NULL;
-        p->hostname = NULL;
-        p->cs_link = NULL;
-#if IRTCL_GENERIC_FILES
-        p->csFile = 0;
-#endif
-        return TCL_OK;
-    }
     if (p->hostname)
     {
-       logf(LOG_DEBUG, "Closing connection to %s", p->hostname);
-        free (p->hostname);
+        logf(LOG_DEBUG, "Closing connection to %s", p->hostname);
+        xfree (p->hostname);
         p->hostname = NULL;
-#if IRTCL_GENERIC_FILES
-        ir_select_remove_write (p->csFile, p);
-        ir_select_remove (p->csFile, p);
-#else
         ir_select_remove_write (cs_fileno (p->cs_link), p);
         ir_select_remove (cs_fileno (p->cs_link), p);
-#endif
 
         odr_reset (p->odr_in);
 
         assert (p->cs_link);
         cs_close (p->cs_link);
         p->cs_link = NULL;
-#if IRTCL_GENERIC_FILES
-        Tcl_FreeFile (p->csFile);
-        p->csFile = NULL;
-#endif
 
         ODR_MASK_ZERO (&p->options);
         ODR_MASK_SET (&p->options, 0);
@@ -1147,6 +1163,25 @@ static int do_disconnect (void *obj, Tcl_Interp *interp,
         ir_tcl_del_q (p);
     }
     assert (!p->cs_link);
+}
+
+/*
+ * do_disconnect: disconnect method on IR object
+ */
+static int do_disconnect (void *obj, Tcl_Interp *interp,
+                          int argc, char **argv)
+{
+    IrTcl_Obj *p = obj;
+
+    if (argc == 0)
+    {
+        p->state = IR_TCL_R_Idle;
+        p->eventType = NULL;
+        p->hostname = NULL;
+        p->cs_link = NULL;
+        return TCL_OK;
+    }
+    ir_tcl_disconnect (p);
     return TCL_OK;
 }
 
@@ -1164,7 +1199,7 @@ static int do_comstack (void *o, Tcl_Interp *interp,
         return ir_tcl_strdel (interp, &obj->comstackType);
     else if (argc == 3)
     {
-        free (obj->comstackType);
+        xfree (obj->comstackType);
         if (ir_tcl_strdup (interp, &obj->comstackType, argv[2]) == TCL_ERROR)
             return TCL_ERROR;
     }
@@ -1225,7 +1260,7 @@ static int do_callback (void *obj, Tcl_Interp *interp,
         return ir_tcl_strdel (interp, &p->callback);
     if (argc == 3)
     {
-        free (p->callback);
+        xfree (p->callback);
         if (argv[2][0])
         {
             if (ir_tcl_strdup (interp, &p->callback, argv[2]) == TCL_ERROR)
@@ -1254,7 +1289,7 @@ static int do_failback (void *obj, Tcl_Interp *interp,
         return ir_tcl_strdel (interp, &p->failback);
     else if (argc == 3)
     {
-        free (p->failback);
+        xfree (p->failback);
         if (argv[2][0])
         {
             if (ir_tcl_strdup (interp, &p->failback, argv[2]) == TCL_ERROR)
@@ -1283,7 +1318,7 @@ static int do_initResponse (void *obj, Tcl_Interp *interp,
         return ir_tcl_strdel (interp, &p->initResponse);
     if (argc == 3)
     {
-        free (p->initResponse);
+        xfree (p->initResponse);
         if (argv[2][0])
         {
             if (ir_tcl_strdup (interp, &p->initResponse, argv[2]) == TCL_ERROR)
@@ -1370,8 +1405,8 @@ static int do_databaseNames (void *obj, Tcl_Interp *interp,
     if (argc == -1)
     {
         for (i=0; i<p->num_databaseNames; i++)
-            free (p->databaseNames[i]);
-        free (p->databaseNames);
+            xfree (p->databaseNames[i]);
+        xfree (p->databaseNames);
     }
     if (argc <= 0)
     {
@@ -1388,18 +1423,19 @@ static int do_databaseNames (void *obj, Tcl_Interp *interp,
     if (p->databaseNames)
     {
         for (i=0; i<p->num_databaseNames; i++)
-            free (p->databaseNames[i]);
-        free (p->databaseNames);
+            xfree (p->databaseNames[i]);
+        xfree (p->databaseNames);
     }
     p->num_databaseNames = argc - 2;
     p->databaseNames =
-        ir_tcl_malloc (sizeof(*p->databaseNames) * p->num_databaseNames);
+        ir_tcl_malloc (sizeof(*p->databaseNames) * (1+p->num_databaseNames));
     for (i=0; i<p->num_databaseNames; i++)
     {
         if (ir_tcl_strdup (interp, &p->databaseNames[i], argv[2+i]) 
             == TCL_ERROR)
             return TCL_ERROR;
     }
+    p->databaseNames[i] = NULL;
     return TCL_OK;
 }
 
@@ -1416,7 +1452,7 @@ static int do_replaceIndicator (void *obj, Tcl_Interp *interp,
         p->replaceIndicator = 1;
         return TCL_OK;
     }
-    return get_set_int (&p->replaceIndicator, interp, argc, argv);
+    return ir_tcl_get_set_int (&p->replaceIndicator, interp, argc, argv);
 }
 
 /*
@@ -1433,7 +1469,7 @@ static int do_queryType (void *obj, Tcl_Interp *interp,
         return ir_tcl_strdel (interp, &p->queryType);
     if (argc == 3)
     {
-        free (p->queryType);
+        xfree (p->queryType);
         if (ir_tcl_strdup (interp, &p->queryType, argv[2]) == TCL_ERROR)
             return TCL_ERROR;
     }
@@ -1473,7 +1509,7 @@ static int do_smallSetUpperBound (void *o, Tcl_Interp *interp,
         p->smallSetUpperBound = 0;
         return TCL_OK;
     }
-    return get_set_int (&p->smallSetUpperBound, interp, argc, argv);
+    return ir_tcl_get_set_int (&p->smallSetUpperBound, interp, argc, argv);
 }
 
 /*
@@ -1489,7 +1525,7 @@ static int do_largeSetLowerBound (void *o, Tcl_Interp *interp,
         p->largeSetLowerBound = 2;
         return TCL_OK;
     }
-    return get_set_int (&p->largeSetLowerBound, interp, argc, argv);
+    return ir_tcl_get_set_int (&p->largeSetLowerBound, interp, argc, argv);
 }
 
 /*
@@ -1505,7 +1541,7 @@ static int do_mediumSetPresentNumber (void *o, Tcl_Interp *interp,
         p->mediumSetPresentNumber = 0;
         return TCL_OK;
     }
-    return get_set_int (&p->mediumSetPresentNumber, interp, argc, argv);
+    return ir_tcl_get_set_int (&p->mediumSetPresentNumber, interp, argc, argv);
 }
 
 /*
@@ -1525,7 +1561,7 @@ static int do_referenceId (void *obj, Tcl_Interp *interp,
         return ir_tcl_strdel (interp, &p->referenceId);
     if (argc == 3)
     {
-        free (p->referenceId);
+        xfree (p->referenceId);
         if (ir_tcl_strdup (interp, &p->referenceId, argv[2]) == TCL_ERROR)
             return TCL_ERROR;
     }
@@ -1548,13 +1584,13 @@ static int do_preferredRecordSyntax (void *obj, Tcl_Interp *interp,
     }
     else if (argc == -1)
     {
-        free (p->preferredRecordSyntax);
+        xfree (p->preferredRecordSyntax);
         p->preferredRecordSyntax = NULL;
         return TCL_OK;
     }
     if (argc == 3)
     {
-        free (p->preferredRecordSyntax);
+        xfree (p->preferredRecordSyntax);
         p->preferredRecordSyntax = NULL;
         if (argv[2][0] && (p->preferredRecordSyntax = 
                            ir_tcl_malloc (sizeof(*p->preferredRecordSyntax))))
@@ -1562,8 +1598,9 @@ static int do_preferredRecordSyntax (void *obj, Tcl_Interp *interp,
     }
     else if (argc == 2)
     {
-        Tcl_AppendElement (interp, IrTcl_getRecordSyntaxStr
-                           (*p->preferredRecordSyntax));
+        Tcl_AppendElement
+            (interp,!p->preferredRecordSyntax ? "" :
+             IrTcl_getRecordSyntaxStr(*p->preferredRecordSyntax));
     }
     return TCL_OK;
             
@@ -1586,7 +1623,7 @@ static int do_elementSetNames (void *obj, Tcl_Interp *interp,
         return ir_tcl_strdel (interp, &p->elementSetNames);
     if (argc == 3)
     {
-        free (p->elementSetNames);
+        xfree (p->elementSetNames);
         if (ir_tcl_strdup (interp, &p->elementSetNames, argv[2]) == TCL_ERROR)
             return TCL_ERROR;
     }
@@ -1611,7 +1648,7 @@ static int do_smallSetElementSetNames (void *obj, Tcl_Interp *interp,
         return ir_tcl_strdel (interp, &p->smallSetElementSetNames);
     if (argc == 3)
     {
-        free (p->smallSetElementSetNames);
+        xfree (p->smallSetElementSetNames);
         if (ir_tcl_strdup (interp, &p->smallSetElementSetNames,
                            argv[2]) == TCL_ERROR)
             return TCL_ERROR;
@@ -1637,7 +1674,7 @@ static int do_mediumSetElementSetNames (void *obj, Tcl_Interp *interp,
         return ir_tcl_strdel (interp, &p->mediumSetElementSetNames);
     if (argc == 3)
     {
-        free (p->mediumSetElementSetNames);
+        xfree (p->mediumSetElementSetNames);
         if (ir_tcl_strdup (interp, &p->mediumSetElementSetNames,
                            argv[2]) == TCL_ERROR)
             return TCL_ERROR;
@@ -1647,50 +1684,50 @@ static int do_mediumSetElementSetNames (void *obj, Tcl_Interp *interp,
 }
 
 static IrTcl_Method ir_method_tab[] = {
-{ 1, "comstack",                    do_comstack },
-{ 1, "protocol",                    do_protocol },
-{ 0, "failback",                    do_failback },
-{ 0, "failInfo",                    do_failInfo },
-{ 0, "apduInfo",                    do_apduInfo },
-{ 0, "logLevel",                    do_logLevel },
-
-{ 0, "eventType",                   do_eventType },
-{ 1, "connect",                     do_connect },
-{ 0, "protocolVersion",             do_protocolVersion },
-{ 1, "preferredMessageSize",        do_preferredMessageSize },
-{ 1, "maximumRecordSize",           do_maximumRecordSize },
-{ 1, "implementationName",          do_implementationName },
-{ 1, "implementationId",            do_implementationId },
-{ 1, "implementationVersion",       do_implementationVersion },
-{ 0, "targetImplementationName",    do_targetImplementationName },
-{ 0, "targetImplementationId",      do_targetImplementationId },
-{ 0, "targetImplementationVersion", do_targetImplementationVersion },
-{ 0, "userInformationField",        do_userInformationField },
-{ 1, "idAuthentication",            do_idAuthentication },
-{ 0, "options",                     do_options },
-{ 0, "init",                        do_init_request },
-{ 0, "initResult",                  do_initResult },
-{ 0, "disconnect",                  do_disconnect },
-{ 0, "callback",                    do_callback },
-{ 0, "initResponse",                do_initResponse },
-{ 0, "triggerResourceControl",      do_triggerResourceControl },
-{ 0, "initResponse",                do_initResponse },
-{ 0, NULL, NULL}
+{ "comstack",                    do_comstack, NULL },
+{ "protocol",                    do_protocol, NULL },
+{ "failback",                    do_failback, NULL },
+{ "failInfo",                    do_failInfo, NULL },
+{ "apduInfo",                    do_apduInfo, NULL },
+{ "logLevel",                    do_logLevel, NULL },
+
+{ "eventType",                   do_eventType, NULL },
+{ "connect",                     do_connect, NULL },
+{ "protocolVersion",             do_protocolVersion, NULL },
+{ "preferredMessageSize",        do_preferredMessageSize, NULL },
+{ "maximumRecordSize",           do_maximumRecordSize, NULL },
+{ "implementationName",          do_implementationName, NULL },
+{ "implementationId",            do_implementationId, NULL },
+{ "implementationVersion",       do_implementationVersion, NULL },
+{ "targetImplementationName",    do_targetImplementationName, NULL },
+{ "targetImplementationId",      do_targetImplementationId, NULL },
+{ "targetImplementationVersion", do_targetImplementationVersion, NULL},
+{ "userInformationField",        do_userInformationField, NULL},
+{ "idAuthentication",            do_idAuthentication, NULL},
+{ "options",                     do_options, NULL},
+{ "init",                        do_init_request, NULL},
+{ "initResult",                  do_initResult, NULL},
+{ "disconnect",                  do_disconnect, NULL},
+{ "callback",                    do_callback, NULL},
+{ "initResponse",                do_initResponse, NULL},
+{ "triggerResourceControl",      do_triggerResourceControl, NULL},
+{ "initResponse",                do_initResponse, NULL},
+{ NULL, NULL}
 };
 
 static IrTcl_Method ir_set_c_method_tab[] = {
-{ 0, "databaseNames",               do_databaseNames},
-{ 0, "replaceIndicator",            do_replaceIndicator},
-{ 0, "queryType",                   do_queryType },
-{ 0, "preferredRecordSyntax",       do_preferredRecordSyntax },
-{ 0, "smallSetUpperBound",          do_smallSetUpperBound},
-{ 0, "largeSetLowerBound",          do_largeSetLowerBound},
-{ 0, "mediumSetPresentNumber",      do_mediumSetPresentNumber},
-{ 0, "referenceId",                 do_referenceId },
-{ 0, "elementSetNames",             do_elementSetNames },
-{ 0, "smallSetElementSetNames",     do_smallSetElementSetNames },
-{ 0, "mediumSetElementSetNames",    do_mediumSetElementSetNames },
-{ 0, NULL, NULL}
+{ "databaseNames",               do_databaseNames, NULL},
+{ "replaceIndicator",            do_replaceIndicator, NULL},
+{ "queryType",                   do_queryType, NULL},
+{ "preferredRecordSyntax",       do_preferredRecordSyntax, NULL},
+{ "smallSetUpperBound",          do_smallSetUpperBound, NULL},
+{ "largeSetLowerBound",          do_largeSetLowerBound, NULL},
+{ "mediumSetPresentNumber",      do_mediumSetPresentNumber, NULL},
+{ "referenceId",                 do_referenceId, NULL},
+{ "elementSetNames",             do_elementSetNames, NULL},
+{ "smallSetElementSetNames",     do_smallSetElementSetNames, NULL},
+{ "mediumSetElementSetNames",    do_mediumSetElementSetNames, NULL},
+{ NULL, NULL}
 };
 
 /* 
@@ -1701,17 +1738,19 @@ static int ir_obj_method (ClientData clientData, Tcl_Interp *interp,
 {
     IrTcl_Methods tab[3];
     IrTcl_Obj *p = clientData;
+    int r;
 
     if (argc < 2)
-        return ir_method_r (clientData, interp, argc, argv, ir_method_tab);
-
+        return TCL_ERROR;
+    
     tab[0].tab = ir_method_tab;
     tab[0].obj = p;
     tab[1].tab = ir_set_c_method_tab;
     tab[1].obj = &p->set_inher;
     tab[2].tab = NULL;
-
-    return ir_method (interp, argc, argv, tab);
+    
+    ir_tcl_method (interp, argc, argv, tab, &r);
+    return r;
 }
 
 /* 
@@ -1734,20 +1773,21 @@ static void ir_obj_delete (ClientData clientData)
     tab[1].obj = &obj->set_inher;
     tab[2].tab = NULL;
 
-    ir_method (NULL, -1, NULL, tab);
+    ir_tcl_method (NULL, -1, NULL, tab, NULL);
 
     ir_tcl_del_q (obj);
     odr_destroy (obj->odr_in);
     odr_destroy (obj->odr_out);
     odr_destroy (obj->odr_pr);
-    free (obj);
+    xfree (obj);
 }
 
 /* 
- * ir_obj_mk: IR Object creation
+ * ir_obj_init: IR Object initialization
  */
-static int ir_obj_mk (ClientData clientData, Tcl_Interp *interp,
-                      int argc, char **argv)
+int ir_obj_init (ClientData clientData, Tcl_Interp *interp,
+                 int argc, char **argv, ClientData *subData,
+                 ClientData parentData)
 {
     IrTcl_Methods tab[3];
     IrTcl_Obj *obj;
@@ -1788,13 +1828,40 @@ static int ir_obj_mk (ClientData clientData, Tcl_Interp *interp,
     tab[1].obj = &obj->set_inher;
     tab[2].tab = NULL;
 
-    if (ir_method (interp, 0, NULL, tab) == TCL_ERROR)
+    if (ir_tcl_method (interp, 0, NULL, tab, NULL) == TCL_ERROR)
+    {
+        Tcl_AppendResult (interp, "Failed to initialize ", argv[1], NULL);
+        return TCL_ERROR;
+    }
+    *subData = obj;
+    return TCL_OK;
+}
+
+
+/* 
+ * ir_obj_mk: IR Object creation
+ */
+static int ir_obj_mk (ClientData clientData, Tcl_Interp *interp,
+                      int argc, char **argv)
+{
+    ClientData subData;
+    int r = ir_obj_init (clientData, interp, argc, argv, &subData, 0);
+    
+    if (r == TCL_ERROR)
         return TCL_ERROR;
     Tcl_CreateCommand (interp, argv[1], ir_obj_method,
-                       (ClientData) obj, ir_obj_delete);
+                       subData, ir_obj_delete);
     return TCL_OK;
 }
 
+IrTcl_Class ir_obj_class = {
+    "ir",
+    ir_obj_init,
+    ir_obj_method,
+    ir_obj_delete
+};
+
+
 /* ------------------------------------------------------- */
 /*
  * do_search: Do search request
@@ -1808,7 +1875,6 @@ static int do_search (void *o, Tcl_Interp *interp, int argc, char **argv)
     IrTcl_SetObj *obj = o;
     IrTcl_Obj *p;
     int r;
-    oident bib1;
 
     if (argc <= 0)
         return TCL_OK;
@@ -1816,9 +1882,11 @@ static int do_search (void *o, Tcl_Interp *interp, int argc, char **argv)
     p = obj->parent;
     if (argc != 3)
     {
+        logf (LOG_DEBUG, "search %s", *argv);
         interp->result = "wrong # args";
         return TCL_ERROR;
     }
+    logf (LOG_DEBUG, "search %s %s", *argv, argv[2]);
     if (!obj->set_inher.num_databaseNames)
     {
         interp->result = "no databaseNames";
@@ -1834,10 +1902,6 @@ static int do_search (void *o, Tcl_Interp *interp, int argc, char **argv)
 
     obj->start = 1;
 
-    bib1.proto = p->protocol_type;
-    bib1.oclass = CLASS_ATTSET;
-    bib1.value = VAL_BIB1;
-
     set_referenceId (p->odr_out, &req->referenceId,
                      obj->set_inher.referenceId);
 
@@ -1890,21 +1954,20 @@ static int do_search (void *o, Tcl_Interp *interp, int argc, char **argv)
         req->mediumSetElementSetNames = NULL; 
     
     req->query = &query;
-    
+   
+    logf (LOG_DEBUG, "queryType %s", obj->set_inher.queryType);
     if (!strcmp (obj->set_inher.queryType, "rpn"))
     {
         Z_RPNQuery *RPNquery;
 
-        RPNquery = p_query_rpn (p->odr_out, argv[2]);
+        RPNquery = p_query_rpn (p->odr_out, p->protocol_type, argv[2]);
         if (!RPNquery)
         {
             Tcl_AppendResult (interp, "Syntax error in query", NULL);
             return TCL_ERROR;
         }
-        RPNquery->attributeSetId = oid_getoidbyent (&bib1);
         query.which = Z_Query_type_1;
         query.u.type_1 = RPNquery;
-        logf (LOG_DEBUG, "RPN");
     }
 #if CCL2RPN
     else if (!strcmp (obj->set_inher.queryType, "cclrpn"))
@@ -1913,6 +1976,11 @@ static int do_search (void *o, Tcl_Interp *interp, int argc, char **argv)
         int pos;
         struct ccl_rpn_node *rpn;
         Z_RPNQuery *RPNquery;
+        oident bib1;
+
+        bib1.proto = p->protocol_type;
+        bib1.oclass = CLASS_ATTSET;
+        bib1.value = VAL_BIB1;
 
         rpn = ccl_find_str(p->bibset, argv[2], &error, &pos);
         if (error)
@@ -1921,13 +1989,14 @@ static int do_search (void *o, Tcl_Interp *interp, int argc, char **argv)
                               ccl_err_msg(error), NULL);
             return TCL_ERROR;
         }
+#if 0
         ccl_pr_tree (rpn, stderr);
         fprintf (stderr, "\n");
+#endif
         assert((RPNquery = ccl_rpn_query(rpn)));
         RPNquery->attributeSetId = oid_getoidbyent (&bib1);
         query.which = Z_Query_type_1;
         query.u.type_1 = RPNquery;
-        logf (LOG_DEBUG, "CCLRPN");
     }
 #endif
     else if (!strcmp (obj->set_inher.queryType, "ccl"))
@@ -1936,7 +2005,6 @@ static int do_search (void *o, Tcl_Interp *interp, int argc, char **argv)
         query.u.type_2 = &ccl_query;
         ccl_query.buf = (unsigned char *) argv[2];
         ccl_query.len = strlen (argv[2]);
-        logf (LOG_DEBUG, "CCL");
     }
     else
     {
@@ -1963,7 +2031,7 @@ static int do_searchResponse (void *o, Tcl_Interp *interp,
         return ir_tcl_strdel (interp, &obj->searchResponse);
     if (argc == 3)
     {
-        free (obj->searchResponse);
+        xfree (obj->searchResponse);
         if (argv[2][0])
         {
             if (ir_tcl_strdup (interp, &obj->searchResponse, argv[2])
@@ -1993,7 +2061,7 @@ static int do_presentResponse (void *o, Tcl_Interp *interp,
         return ir_tcl_strdel (interp, &obj->presentResponse);
     if (argc == 3)
     {
-        free (obj->presentResponse);
+        xfree (obj->presentResponse);
         if (argv[2][0])
         {
             if (ir_tcl_strdup (interp, &obj->presentResponse, argv[2])
@@ -2019,7 +2087,7 @@ static int do_resultCount (void *o, Tcl_Interp *interp,
         obj->resultCount = 0;
         return TCL_OK;
     }
-    return get_set_int (&obj->resultCount, interp, argc, argv);
+    return ir_tcl_get_set_int (&obj->resultCount, interp, argc, argv);
 }
 
 /*
@@ -2032,7 +2100,7 @@ static int do_searchStatus (void *o, Tcl_Interp *interp,
 
     if (argc <= 0)
         return TCL_OK;
-    return get_set_int (&obj->searchStatus, interp, argc, argv);
+    return ir_tcl_get_set_int (&obj->searchStatus, interp, argc, argv);
 }
 
 /*
@@ -2045,7 +2113,7 @@ static int do_presentStatus (void *o, Tcl_Interp *interp,
 
     if (argc <= 0)
         return TCL_OK;
-    return get_set_int (&obj->presentStatus, interp, argc, argv);
+    return ir_tcl_get_set_int (&obj->presentStatus, interp, argc, argv);
 }
 
 /*
@@ -2062,7 +2130,8 @@ static int do_nextResultSetPosition (void *o, Tcl_Interp *interp,
         obj->nextResultSetPosition = 0;
         return TCL_OK;
     }
-    return get_set_int (&obj->nextResultSetPosition, interp, argc, argv);
+    return ir_tcl_get_set_int (&obj->nextResultSetPosition, interp,
+                               argc, argv);
 }
 
 /*
@@ -2079,7 +2148,7 @@ static int do_setName (void *o, Tcl_Interp *interp,
         return ir_tcl_strdel (interp, &obj->setName);
     if (argc == 3)
     {
-        free (obj->setName);
+        xfree (obj->setName);
         if (ir_tcl_strdup (interp, &obj->setName, argv[2])
             == TCL_ERROR)
             return TCL_ERROR;
@@ -2101,7 +2170,8 @@ static int do_numberOfRecordsReturned (void *o, Tcl_Interp *interp,
         obj->numberOfRecordsReturned = 0;
         return TCL_OK;
     }
-    return get_set_int (&obj->numberOfRecordsReturned, interp, argc, argv);
+    return ir_tcl_get_set_int (&obj->numberOfRecordsReturned, interp,
+                               argc, argv);
 }
 
 /*
@@ -2208,7 +2278,7 @@ static int do_recordElements (void *o, Tcl_Interp *interp,
     }
     if (argc == 3)
     {
-        free (obj->recordElements);
+        xfree (obj->recordElements);
         return ir_tcl_strdup (NULL, &obj->recordElements, 
                               (*argv[2] ? argv[2] : NULL));
     }
@@ -2227,7 +2297,6 @@ static int ir_diagResult (Tcl_Interp *interp, IrTcl_Diagnostic *list, int num)
 
     for (i = 0; i<num; i++)
     {
-        logf (LOG_DEBUG, "Diagnostic, code %d", list[i].condition);
         sprintf (buf, "%d", list[i].condition);
         Tcl_AppendElement (interp, buf);
         cp = diagbib1_str (list[i].condition);
@@ -2447,6 +2516,7 @@ static int do_present (void *o, Tcl_Interp *interp, int argc, char **argv)
     }
     else 
         number = 10;
+    logf (LOG_DEBUG, "present %s %d %d", *argv, start, number);
     p = obj->parent;
     if (!p->cs_link)
     {
@@ -2540,26 +2610,26 @@ static int do_loadFile (void *o, Tcl_Interp *interp,
 }
 
 static IrTcl_Method ir_set_method_tab[] = {
-    { 0, "search",                  do_search },
-    { 0, "searchResponse",          do_searchResponse },
-    { 0, "presentResponse",         do_presentResponse },
-    { 0, "searchStatus",            do_searchStatus },
-    { 0, "presentStatus",           do_presentStatus },
-    { 0, "nextResultSetPosition",   do_nextResultSetPosition },
-    { 0, "setName",                 do_setName },
-    { 0, "resultCount",             do_resultCount },
-    { 0, "numberOfRecordsReturned", do_numberOfRecordsReturned },
-    { 0, "present",                 do_present },
-    { 0, "type",                    do_type },
-    { 0, "getMarc",                 do_getMarc },
-    { 0, "getSutrs",                do_getSutrs },
-    { 0, "getGrs",                  do_getGrs },
-    { 0, "recordType",              do_recordType },
-    { 0, "recordElements",          do_recordElements },
-    { 0, "diag",                    do_diag },
-    { 0, "responseStatus",          do_responseStatus },
-    { 0, "loadFile",                do_loadFile },
-    { 0, NULL, NULL}
+    { "search",                  do_search, NULL},
+    { "searchResponse",          do_searchResponse, NULL},
+    { "presentResponse",         do_presentResponse, NULL},
+    { "searchStatus",            do_searchStatus, NULL},
+    { "presentStatus",           do_presentStatus, NULL},
+    { "nextResultSetPosition",   do_nextResultSetPosition, NULL},
+    { "setName",                 do_setName, NULL},
+    { "resultCount",             do_resultCount, NULL},
+    { "numberOfRecordsReturned", do_numberOfRecordsReturned, NULL},
+    { "present",                 do_present, NULL},
+    { "type",                    do_type, NULL},
+    { "getMarc",                 do_getMarc, NULL},
+    { "getSutrs",                do_getSutrs, NULL},
+    { "getGrs",                  do_getGrs, NULL},
+    { "recordType",              do_recordType, NULL},
+    { "recordElements",          do_recordElements, NULL},
+    { "diag",                    do_diag, NULL},
+    { "responseStatus",          do_responseStatus, NULL},
+    { "loadFile",                do_loadFile, NULL},
+    { NULL, NULL}
 };
 
 /* 
@@ -2570,6 +2640,7 @@ static int ir_set_obj_method (ClientData clientData, Tcl_Interp *interp,
 {
     IrTcl_Methods tabs[3];
     IrTcl_SetObj *p = clientData;
+    int r;
 
     if (argc < 2)
     {
@@ -2582,7 +2653,8 @@ static int ir_set_obj_method (ClientData clientData, Tcl_Interp *interp,
     tabs[1].obj = &p->set_inher;
     tabs[2].tab = NULL;
 
-    return ir_method (interp, argc, argv, tabs);
+    ir_tcl_method (interp, argc, argv, tabs, &r);
+    return r;
 }
 
 /* 
@@ -2601,16 +2673,17 @@ static void ir_set_obj_delete (ClientData clientData)
     tabs[1].obj = &p->set_inher;
     tabs[2].tab = NULL;
 
-    ir_method (NULL, -1, NULL, tabs);
+    ir_tcl_method (NULL, -1, NULL, tabs, NULL);
 
-    free (p);
+    xfree (p);
 }
 
 /*
- * ir_set_obj_mk: IR Set Object creation
+ * ir_set_obj_init: IR Set Object initialization
  */
-static int ir_set_obj_mk (ClientData clientData, Tcl_Interp *interp,
-                          int argc, char **argv)
+static int ir_set_obj_init (ClientData clientData, Tcl_Interp *interp,
+                            int argc, char **argv, ClientData *subData,
+                            ClientData parentData)
 {
     IrTcl_Methods tabs[3];
     IrTcl_SetObj *obj;
@@ -2621,34 +2694,31 @@ static int ir_set_obj_mk (ClientData clientData, Tcl_Interp *interp,
         return TCL_ERROR;
     }
     obj = ir_tcl_malloc (sizeof(*obj));
-    logf (LOG_DEBUG, "ir set create");
-    if (argc == 3)
+    logf (LOG_DEBUG, "ir set create %s", argv[1]);
+    if (parentData)
     {
-        Tcl_CmdInfo parent_info;
         int i;
         IrTcl_SetCObj *dst;
         IrTcl_SetCObj *src;
 
-        if (!Tcl_GetCommandInfo (interp, argv[2], &parent_info))
-        {
-            interp->result = "No parent";
-            return TCL_ERROR;
-        }
-        obj->parent = (IrTcl_Obj *) parent_info.clientData;
+        obj->parent = (IrTcl_Obj *) parentData;
 
         dst = &obj->set_inher;
         src = &obj->parent->set_inher;
 
         if ((dst->num_databaseNames = src->num_databaseNames))
+        {
             dst->databaseNames =
                 ir_tcl_malloc (sizeof (*dst->databaseNames)
-                               * dst->num_databaseNames);
+                               * (1+dst->num_databaseNames));
+            for (i = 0; i < dst->num_databaseNames; i++)
+                if (ir_tcl_strdup (interp, &dst->databaseNames[i],
+                                   src->databaseNames[i]) == TCL_ERROR)
+                    return TCL_ERROR;
+            dst->databaseNames[i] = NULL;
+        }
         else
             dst->databaseNames = NULL;
-        for (i = 0; i < dst->num_databaseNames; i++)
-            if (ir_tcl_strdup (interp, &dst->databaseNames[i],
-                           src->databaseNames[i]) == TCL_ERROR)
-                return TCL_ERROR;
         if (ir_tcl_strdup (interp, &dst->queryType, src->queryType)
             == TCL_ERROR)
             return TCL_ERROR;
@@ -2689,14 +2759,48 @@ static int ir_set_obj_mk (ClientData clientData, Tcl_Interp *interp,
     tabs[0].obj = obj;
     tabs[1].tab = NULL;
 
-    if (ir_method (interp, 0, NULL, tabs) == TCL_ERROR)
+    if (ir_tcl_method (interp, 0, NULL, tabs, NULL) == TCL_ERROR)
         return TCL_ERROR;
 
+    *subData = obj;
+    return TCL_OK;
+}
+
+/*
+ * ir_set_obj_mk: IR Set Object creation
+ */
+static int ir_set_obj_mk (ClientData clientData, Tcl_Interp *interp,
+                          int argc, char **argv)
+{
+    ClientData subData;
+    ClientData parentData = 0;
+    int r;
+
+    if (argc == 3)
+    {
+        Tcl_CmdInfo parent_info;
+        if (!Tcl_GetCommandInfo (interp, argv[2], &parent_info))
+        {
+            interp->result = "No parent";
+            return TCL_ERROR;
+        }
+        parentData = parent_info.clientData;
+    }
+    r = ir_set_obj_init (clientData, interp, argc, argv, &subData, parentData);
+    if (r == TCL_ERROR)
+        return TCL_ERROR;
     Tcl_CreateCommand (interp, argv[1], ir_set_obj_method,
-                       (ClientData) obj, ir_set_obj_delete);
+                       subData, ir_set_obj_delete);
     return TCL_OK;
 }
 
+IrTcl_Class ir_set_obj_class = {
+    "ir-set",
+    ir_set_obj_init,
+    ir_set_obj_method,
+    ir_set_obj_delete
+};
+
 /* ------------------------------------------------------- */
 
 /*
@@ -2708,8 +2812,8 @@ static int do_scan (void *o, Tcl_Interp *interp, int argc, char **argv)
     Z_APDU *apdu;
     IrTcl_ScanObj *obj = o;
     IrTcl_Obj *p = obj->parent;
-    oident bib1;
 #if CCL2RPN
+    oident bib1;
     struct ccl_rpn_node *rpn;
     int pos;
 #endif
@@ -2721,6 +2825,7 @@ static int do_scan (void *o, Tcl_Interp *interp, int argc, char **argv)
         interp->result = "wrong # args";
         return TCL_ERROR;
     }
+    logf (LOG_DEBUG, "scan %s %s", *argv, argv[2]);
     if (!p->set_inher.num_databaseNames)
     {
         interp->result = "no databaseNames";
@@ -2732,20 +2837,17 @@ static int do_scan (void *o, Tcl_Interp *interp, int argc, char **argv)
         return TCL_ERROR;
     }
 
-    bib1.proto = p->protocol_type;
-    bib1.oclass = CLASS_ATTSET;
-    bib1.value = VAL_BIB1;
-
     apdu = zget_APDU (p->odr_out, Z_APDU_scanRequest);
     req = apdu->u.scanRequest;
 
     set_referenceId (p->odr_out, &req->referenceId, p->set_inher.referenceId);
     req->num_databaseNames = p->set_inher.num_databaseNames;
     req->databaseNames = p->set_inher.databaseNames;
-    req->attributeSet = oid_getoidbyent (&bib1);
 
 #if !CCL2RPN
-    if (!(req->termListAndStartPoint = p_query_scan (p->odr_out, argv[2])))
+    if (!(req->termListAndStartPoint =
+          p_query_scan (p->odr_out, p->protocol_type,
+                        &req->attributeSet, argv[2])))
     {
         Tcl_AppendResult (interp, "Syntax error in query", NULL);
         return TCL_ERROR;
@@ -2757,8 +2859,11 @@ static int do_scan (void *o, Tcl_Interp *interp, int argc, char **argv)
         Tcl_AppendResult (interp, "CCL error: ", ccl_err_msg (r), NULL);
         return TCL_ERROR;
     }
-    ccl_pr_tree (rpn, stderr);
-    fprintf (stderr, "\n");
+    bib1.proto = p->protocol_type;
+    bib1.oclass = CLASS_ATTSET;
+    bib1.value = VAL_BIB1;
+
+    req->attributeSet = oid_getoidbyent (&bib1);
     if (!(req->termListAndStartPoint = ccl_scan_query (rpn)))
         return TCL_ERROR;
 #endif
@@ -2791,7 +2896,7 @@ static int do_scanResponse (void *o, Tcl_Interp *interp,
         return ir_tcl_strdel (interp, &obj->scanResponse);
     if (argc == 3)
     {
-        free (obj->scanResponse);
+        xfree (obj->scanResponse);
         if (argv[2][0])
         {
             if (ir_tcl_strdup (interp, &obj->scanResponse, argv[2])
@@ -2816,7 +2921,7 @@ static int do_stepSize (void *obj, Tcl_Interp *interp,
         p->stepSize = 0;
         return TCL_OK;
     }
-    return get_set_int (&p->stepSize, interp, argc, argv);
+    return ir_tcl_get_set_int (&p->stepSize, interp, argc, argv);
 }
 
 /*
@@ -2832,7 +2937,7 @@ static int do_numberOfTermsRequested (void *obj, Tcl_Interp *interp,
         p->numberOfTermsRequested = 20;
         return TCL_OK;
     }
-    return get_set_int (&p->numberOfTermsRequested, interp, argc, argv);
+    return ir_tcl_get_set_int (&p->numberOfTermsRequested, interp, argc, argv);
 }
 
 
@@ -2849,7 +2954,8 @@ static int do_preferredPositionInResponse (void *obj, Tcl_Interp *interp,
         p->preferredPositionInResponse = 1;
         return TCL_OK;
     }
-    return get_set_int (&p->preferredPositionInResponse, interp, argc, argv);
+    return ir_tcl_get_set_int (&p->preferredPositionInResponse, interp,
+                               argc, argv);
 }
 
 /*
@@ -2862,7 +2968,7 @@ static int do_scanStatus (void *obj, Tcl_Interp *interp,
 
     if (argc <= 0)
         return TCL_OK;
-    return get_set_int (&p->scanStatus, interp, argc, argv);
+    return ir_tcl_get_set_int (&p->scanStatus, interp, argc, argv);
 }
 
 /*
@@ -2875,7 +2981,8 @@ static int do_numberOfEntriesReturned (void *obj, Tcl_Interp *interp,
 
     if (argc <= 0)
         return TCL_OK;
-    return get_set_int (&p->numberOfEntriesReturned, interp, argc, argv);
+    return ir_tcl_get_set_int (&p->numberOfEntriesReturned, interp,
+                               argc, argv);
 }
 
 /*
@@ -2888,7 +2995,7 @@ static int do_positionOfTerm (void *obj, Tcl_Interp *interp,
 
     if (argc <= 0)
         return TCL_OK;
-    return get_set_int (&p->positionOfTerm, interp, argc, argv);
+    return ir_tcl_get_set_int (&p->positionOfTerm, interp, argc, argv);
 }
 
 /*
@@ -2949,16 +3056,16 @@ static int do_scanLine (void *obj, Tcl_Interp *interp, int argc, char **argv)
 }
 
 static IrTcl_Method ir_scan_method_tab[] = {
-    { 0, "scan",                    do_scan },
-    { 0, "scanResponse",            do_scanResponse },
-    { 0, "stepSize",                do_stepSize },
-    { 0, "numberOfTermsRequested",  do_numberOfTermsRequested },
-    { 0, "preferredPositionInResponse", do_preferredPositionInResponse },
-    { 0, "scanStatus",              do_scanStatus },
-    { 0, "numberOfEntriesReturned", do_numberOfEntriesReturned },
-    { 0, "positionOfTerm",          do_positionOfTerm },
-    { 0, "scanLine",                do_scanLine },
-    { 0, NULL, NULL}
+    { "scan",                    do_scan, NULL},
+    { "scanResponse",            do_scanResponse, NULL},
+    { "stepSize",                do_stepSize, NULL},
+    { "numberOfTermsRequested",  do_numberOfTermsRequested, NULL},
+    { "preferredPositionInResponse", do_preferredPositionInResponse, NULL},
+    { "scanStatus",              do_scanStatus, NULL},
+    { "numberOfEntriesReturned", do_numberOfEntriesReturned, NULL},
+    { "positionOfTerm",          do_positionOfTerm, NULL},
+    { "scanLine",                do_scanLine, NULL},
+    { NULL, NULL}
 };
 
 /* 
@@ -2968,6 +3075,7 @@ static int ir_scan_obj_method (ClientData clientData, Tcl_Interp *interp,
                                int argc, char **argv)
 {
     IrTcl_Methods tabs[2];
+    int r;
 
     if (argc < 2)
     {
@@ -2978,7 +3086,8 @@ static int ir_scan_obj_method (ClientData clientData, Tcl_Interp *interp,
     tabs[0].obj = clientData;
     tabs[1].tab = NULL;
 
-    return ir_method (interp, argc, argv, tabs);
+    ir_tcl_method (interp, argc, argv, tabs, &r);
+    return r;
 }
 
 /* 
@@ -2993,8 +3102,8 @@ static void ir_scan_obj_delete (ClientData clientData)
     tabs[0].obj = obj;
     tabs[1].tab = NULL;
 
-    ir_method (NULL, -1, NULL, tabs);
-    free (obj);
+    ir_tcl_method (NULL, -1, NULL, tabs, NULL);
+    xfree (obj);
 }
 
 /* 
@@ -3012,6 +3121,7 @@ static int ir_scan_obj_mk (ClientData clientData, Tcl_Interp *interp,
         interp->result = "wrong # args";
         return TCL_ERROR;
     }
+    logf (LOG_DEBUG, "ir scan create %s", argv[1]);
     if (!Tcl_GetCommandInfo (interp, argv[2], &parent_info))
     {
         interp->result = "No parent";
@@ -3024,7 +3134,7 @@ static int ir_scan_obj_mk (ClientData clientData, Tcl_Interp *interp,
     tabs[0].obj = obj;
     tabs[1].tab = NULL;
 
-    if (ir_method (interp, 0, NULL, tabs) == TCL_ERROR)
+    if (ir_tcl_method (interp, 0, NULL, tabs, NULL) == TCL_ERROR)
         return TCL_ERROR;
     Tcl_CreateCommand (interp, argv[1], ir_scan_obj_method,
                        (ClientData) obj, ir_scan_obj_delete);
@@ -3045,13 +3155,13 @@ static void ir_initResponse (void *obj, Z_InitResponse *initrs)
 
     get_referenceId (&p->set_inher.referenceId, initrs->referenceId);
 
-    free (p->targetImplementationId);
+    xfree (p->targetImplementationId);
     ir_tcl_strdup (p->interp, &p->targetImplementationId,
                initrs->implementationId);
-    free (p->targetImplementationName);
+    xfree (p->targetImplementationName);
     ir_tcl_strdup (p->interp, &p->targetImplementationName,
                initrs->implementationName);
-    free (p->targetImplementationVersion);
+    xfree (p->targetImplementationVersion);
     ir_tcl_strdup (p->interp, &p->targetImplementationVersion,
                initrs->implementationVersion);
 
@@ -3061,7 +3171,7 @@ static void ir_initResponse (void *obj, Z_InitResponse *initrs)
     memcpy (&p->options, initrs->options, sizeof(initrs->options));
     memcpy (&p->protocolVersion, initrs->protocolVersion,
             sizeof(initrs->protocolVersion));
-    free (p->userInformationField);
+    xfree (p->userInformationField);
     p->userInformationField = NULL;
     if (initrs->userInformationField)
     {
@@ -3085,8 +3195,8 @@ static void ir_deleteDiags (IrTcl_Diagnostic **dst_list, int *dst_num)
 {
     int i;
     for (i = 0; i<*dst_num; i++)
-        free (dst_list[i]->addinfo);
-    free (*dst_list);
+        xfree (dst_list[i]->addinfo);
+    xfree (*dst_list);
     *dst_list = NULL;
     *dst_num = 0;
 }
@@ -3101,6 +3211,7 @@ static void ir_handleDiags (IrTcl_Diagnostic **dst_list, int *dst_num,
     *dst_list = ir_tcl_malloc (sizeof(**dst_list) * num);
     for (i = 0; i<num; i++)
     {
+        const char *cp;
         switch (list[i]->which)
         {
         case Z_DiagRec_defaultFormat:
@@ -3109,6 +3220,9 @@ static void ir_handleDiags (IrTcl_Diagnostic **dst_list, int *dst_num,
             if (addinfo && 
                 ((*dst_list)[i].addinfo = ir_tcl_malloc (strlen(addinfo)+1)))
                 strcpy ((*dst_list)[i].addinfo, addinfo);
+            cp = diagbib1_str ((*dst_list)[i].condition);
+            logf (LOG_DEBUG, "Diag %d %s %s", (*dst_list)[i].condition,
+                  cp ? cp : "", addinfo ? addinfo : "");
             break;
         default:
             (*dst_list)[i].addinfo = NULL;
@@ -3187,7 +3301,7 @@ static void ir_handleRecords (void *o, Z_Records *zrs, IrTcl_SetObj *setobj,
                 else if (rl->u.dbrec.type == VAL_GRS1 && 
                          oe->which == Z_External_grs1)
                 {
-                    ir_tcl_read_grs (oe->u.grs1, &rl->u.dbrec.u.grs1);
+                    ir_tcl_grs_mk (oe->u.grs1, &rl->u.dbrec.u.grs1);
                     rl->u.dbrec.buf = NULL;
                 }
                 else
@@ -3235,7 +3349,7 @@ static void ir_searchResponse (void *o, Z_SearchResponse *searchrs,
     if (searchrs->nextResultSetPosition)
         setobj->nextResultSetPosition = *searchrs->nextResultSetPosition;
 
-    logf (LOG_DEBUG, "Search response %d, %d hits", 
+    logf (LOG_DEBUG, "status %d hits %d", 
           setobj->searchStatus, setobj->resultCount);
     if (zrs)
     {
@@ -3299,7 +3413,7 @@ static void ir_scanResponse (void *o, Z_ScanResponse *scanrs,
         scanobj->positionOfTerm = -1;
     logf (LOG_DEBUG, "positionOfTerm=%d", scanobj->positionOfTerm);
 
-    free (scanobj->entries);
+    xfree (scanobj->entries);
     scanobj->entries = NULL;
 
     ir_deleteDiags (&scanobj->nonSurrogateDiagnosticList,
@@ -3367,7 +3481,7 @@ static void ir_scanResponse (void *o, Z_ScanResponse *scanrs,
 /*
  * ir_select_read: handle incoming packages
  */
-void ir_select_read (ClientData clientData)
+static void ir_select_read (ClientData clientData)
 {
     IrTcl_Obj *p = clientData;
     Z_APDU *apdu;
@@ -3380,7 +3494,7 @@ void ir_select_read (ClientData clientData)
     logf(LOG_DEBUG, "Read handler fd=%d", cs_fileno(p->cs_link));
     if (p->state == IR_TCL_R_Connecting)
     {
-       logf(LOG_DEBUG, "Connect handler");
+        logf(LOG_DEBUG, "read: connect");
         r = cs_rcvconnect (p->cs_link);
         if (r == 1)
         {
@@ -3388,60 +3502,55 @@ void ir_select_read (ClientData clientData)
             return;
         }
         p->state = IR_TCL_R_Idle;
-#if IRTCL_GENERIC_FILES
-        ir_select_remove_write (p->csFile, p);
-#else
+        p->ref_count = 2;
         ir_select_remove_write (cs_fileno (p->cs_link), p);
-#endif
         if (r < 0)
         {
             logf (LOG_DEBUG, "cs_rcvconnect error");
+            ir_tcl_disconnect (p);
             if (p->failback)
             {
                 p->failInfo = IR_TCL_FAIL_CONNECT;
-                IrTcl_eval (p->interp, p->failback);
+                ir_tcl_eval (p->interp, p->failback);
             }
-            do_disconnect (p, NULL, 2, NULL);
+            ir_obj_delete (p);
             return;
         }
-        p->state = IR_TCL_R_Idle;
         if (p->callback)
-            IrTcl_eval (p->interp, p->callback);
-        if (p->cs_link && p->request_queue && p->state == IR_TCL_R_Idle)
+            ir_tcl_eval (p->interp, p->callback);
+        if (p->ref_count == 2 && p->cs_link && p->request_queue
+            && p->state == IR_TCL_R_Idle)
             ir_tcl_send_q (p, p->request_queue, "x");
+        ir_obj_delete (p);
         return;
     }
     do
     {
-        /* signal one more use of ir object - callbacks must not
-           release the ir memory (p pointer) */
         p->state = IR_TCL_R_Reading;
-        ++(p->ref_count);
 
         /* read incoming APDU */
-        if ((r=cs_get (p->cs_link, &p->buf_in, &p->len_in)) <= 0)
+        if ((r=cs_get (p->cs_link, &p->buf_in, &p->len_in)) == 1)
+        {
+            logf(LOG_DEBUG, "PDU Fraction read");
+            return ;
+        }
+        /* signal one more use of ir object - callbacks must not
+           release the ir memory (p pointer) */
+        p->ref_count = 2;
+        if (r <= 0)
         {
             logf (LOG_DEBUG, "cs_get failed, code %d", r);
-#if IRTCL_GENERIC_FILES
-            ir_select_remove (p->csFile, p);
-#else
             ir_select_remove (cs_fileno (p->cs_link), p);
-#endif
-            do_disconnect (p, NULL, 2, NULL);
+            ir_tcl_disconnect (p);
             if (p->failback)
             {
                 p->failInfo = IR_TCL_FAIL_READ;
-                IrTcl_eval (p->interp, p->failback);
+                ir_tcl_eval (p->interp, p->failback);
             }
             /* release ir object now if callback deleted it */
             ir_obj_delete (p);
             return;
         }        
-        if (r == 1)
-       {
-           logf(LOG_DEBUG, "PDU Fraction read");
-            return ;
-       }
         /* got complete APDU. Now decode */
         p->apduLen = r;
         p->apduOffset = -1;
@@ -3450,19 +3559,18 @@ void ir_select_read (ClientData clientData)
         if (!z_APDU (p->odr_in, &apdu, 0))
         {
             logf (LOG_DEBUG, "cs_get failed: %s",
-               odr_errmsg (odr_geterror (p->odr_in)));
-            do_disconnect (p, NULL, 2, NULL);
+                odr_errmsg (odr_geterror (p->odr_in)));
+            ir_tcl_disconnect (p);
             if (p->failback)
             {
                 p->failInfo = IR_TCL_FAIL_IN_APDU;
                 p->apduOffset = odr_offset (p->odr_in);
-                IrTcl_eval (p->interp, p->failback);
+                ir_tcl_eval (p->interp, p->failback);
             }
             /* release ir object now if failback deleted it */
             ir_obj_delete (p);
             return;
         }
-       logf(LOG_DEBUG, "Decoded ok");
         /* handle APDU and invoke callback */
         rq = p->request_queue;
         if (!rq)
@@ -3471,7 +3579,7 @@ void ir_select_read (ClientData clientData)
             exit (1);
         }
         object_name = rq->object_name;
-        logf (LOG_DEBUG, "getCommandInfo (%s)", object_name);
+        logf (LOG_DEBUG, "Object %s", object_name);
         apdu_call = NULL;
         if (Tcl_GetCommandInfo (p->interp, object_name, &cmd_info))
         {
@@ -3480,7 +3588,7 @@ void ir_select_read (ClientData clientData)
             case Z_APDU_initResponse:
                 p->eventType = "init";
                 ir_initResponse (p, apdu->u.initResponse);
-               apdu_call = p->initResponse;
+                apdu_call = p->initResponse;
                 break;
             case Z_APDU_searchResponse:
                 p->eventType = "search";
@@ -3506,11 +3614,11 @@ void ir_select_read (ClientData clientData)
             default:
                 logf (LOG_WARN, "Received unknown APDU type (%d)",
                       apdu->which);
-                do_disconnect (p, NULL, 2, NULL);
+                ir_tcl_disconnect (p);
                 if (p->failback)
                 {
                     p->failInfo = IR_TCL_FAIL_UNKNOWN_APDU;
-                    IrTcl_eval (p->interp, p->failback);
+                    ir_tcl_eval (p->interp, p->failback);
                 }
                 return;
             }
@@ -3519,20 +3627,20 @@ void ir_select_read (ClientData clientData)
         p->state = IR_TCL_R_Idle;
        
         if (apdu_call)
-            IrTcl_eval (p->interp, apdu_call);
+            ir_tcl_eval (p->interp, apdu_call);
         else if (rq->callback)
-            IrTcl_eval (p->interp, rq->callback);
-        free (rq->buf_out);
-        free (rq->callback);
-        free (rq->object_name);
-        free (rq);
+            ir_tcl_eval (p->interp, rq->callback);
+        xfree (rq->buf_out);
+        xfree (rq->callback);
+        xfree (rq->object_name);
+        xfree (rq);
         odr_reset (p->odr_in);
         if (p->ref_count == 1)
         {
             ir_obj_delete (p);
             return;
         }
-        --(p->ref_count);
+        ir_obj_delete (p);
     } while (p->cs_link && cs_more (p->cs_link));
     if (p->cs_link && p->request_queue && p->state == IR_TCL_R_Idle)
         ir_tcl_send_q (p, p->request_queue, "x");
@@ -3541,7 +3649,7 @@ void ir_select_read (ClientData clientData)
 /*
  * ir_select_write: handle outgoing packages - not yet written.
  */
-void ir_select_write (ClientData clientData)
+static int ir_select_write (ClientData clientData)
 {
     IrTcl_Obj *p = clientData;
     int r;
@@ -3550,64 +3658,73 @@ void ir_select_write (ClientData clientData)
     logf (LOG_DEBUG, "Write handler fd=%d", cs_fileno(p->cs_link));
     if (p->state == IR_TCL_R_Connecting)
     {
-       logf(LOG_DEBUG, "Connect handler");
+        logf(LOG_DEBUG, "write: connect");
         r = cs_rcvconnect (p->cs_link);
         if (r == 1)
-            return;
+        {
+            logf (LOG_DEBUG, "cs_rcvconnect returned 1");
+            return 2;
+        }
         p->state = IR_TCL_R_Idle;
+        p->ref_count = 2;
+        ir_select_remove_write (cs_fileno (p->cs_link), p);
         if (r < 0)
         {
             logf (LOG_DEBUG, "cs_rcvconnect error");
-#if IRTCL_GENERIC_FILES
-            ir_select_remove_write (p->csFile, p);
-#else
-            ir_select_remove_write (cs_fileno (p->cs_link), p);
-#endif
+            ir_tcl_disconnect (p);
             if (p->failback)
             {
                 p->failInfo = IR_TCL_FAIL_CONNECT;
-                IrTcl_eval (p->interp, p->failback);
+                ir_tcl_eval (p->interp, p->failback);
             }
-            do_disconnect (p, NULL, 2, NULL);
-            return;
+            ir_obj_delete (p);
+            return 2;
         }
-#if IRTCL_GENERIC_FILES
-        ir_select_remove_write (p->csFile, p);
-#else
-        ir_select_remove_write (cs_fileno (p->cs_link), p);
-#endif
         if (p->callback)
-            IrTcl_eval (p->interp, p->callback);
-        return;
+            ir_tcl_eval (p->interp, p->callback);
+        ir_obj_delete (p);
+        return 2;
     }
     rq = p->request_queue;
     if (!rq || !rq->buf_out)
-        return;
+        return 0;
     assert (rq);
     if ((r=cs_put (p->cs_link, rq->buf_out, rq->len_out)) < 0)
     {
         logf (LOG_DEBUG, "cs_put write fail");
+        p->ref_count = 2;
+        xfree (rq->buf_out);
+        rq->buf_out = NULL;
+        ir_tcl_disconnect (p);
         if (p->failback)
         {
             p->failInfo = IR_TCL_FAIL_WRITE;
-            IrTcl_eval (p->interp, p->failback);
+            ir_tcl_eval (p->interp, p->failback);
         }
-        free (rq->buf_out);
-        rq->buf_out = NULL;
-        do_disconnect (p, NULL, 2, NULL);
+        ir_obj_delete (p);
     }
     else if (r == 0)            /* remove select bit */
     {
-       logf(LOG_DEBUG, "Write completed");
+        logf (LOG_DEBUG, "Write completed");
         p->state = IR_TCL_R_Waiting;
-#if IRTCL_GENERIC_FILES
-        ir_select_remove_write (p->csFile, p);
-#else
         ir_select_remove_write (cs_fileno (p->cs_link), p);
-#endif
-        free (rq->buf_out);
+        xfree (rq->buf_out);
         rq->buf_out = NULL;
     }
+    return 1;
+}
+
+static void ir_select_notify (ClientData clientData, int r, int w, int e)
+{
+    if (w)
+    {
+        if (!ir_select_write (clientData) && r)
+            ir_select_read (clientData);
+    } 
+    else if (r)
+    {
+        ir_select_read (clientData);
+    }
 }
 
 /* ------------------------------------------------------- */