Changed scan response handler.
[ir-tcl-moved-to-github.git] / ir-tcl.c
index efccf01..0784461 100644 (file)
--- a/ir-tcl.c
+++ b/ir-tcl.c
@@ -1,11 +1,44 @@
 /*
  * IR toolkit for tcl/tk
- * (c) Index Data 1995-1996
+ * (c) Index Data 1995-1998
  * See the file LICENSE for details.
  * Sebastian Hammer, Adam Dickmeiss
  *
  * $Log: ir-tcl.c,v $
- * Revision 1.100  1997-05-01 15:04:05  adam
+ * Revision 1.110  1998-10-20 15:15:31  adam
+ * Changed scan response handler.
+ *
+ * Revision 1.109  1998/10/13 21:23:26  adam
+ * Fixed searchStatus method.
+ *
+ * Revision 1.108  1998/10/12 11:48:08  adam
+ * Removed printf call.
+ *
+ * Revision 1.107  1998/06/10 13:00:46  adam
+ * Added ir-version command.
+ *
+ * Revision 1.106  1998/05/20 12:25:35  adam
+ * Fixed bug that occurred in rare cases when encoding of incoming
+ * records failed.
+ *
+ * Revision 1.105  1998/04/02 14:31:08  adam
+ * This version works with compiled ASN.1 code.
+ *
+ * Revision 1.104  1998/02/27 14:26:07  adam
+ * Changed client so that it still works if target sets numberOfRecords
+ * in response to an illegal value.
+ *
+ * Revision 1.103  1997/11/19 11:22:10  adam
+ * Object identifiers can be accessed in GRS-1 records.
+ *
+ * Revision 1.102  1997/09/17 12:22:40  adam
+ * Changed to use YAZ version 1.4. The new comstack utility, cs_straddr,
+ * is used.
+ *
+ * Revision 1.101  1997/09/09 10:19:53  adam
+ * New MSV5.0 port with fewer warnings.
+ *
+ * Revision 1.100  1997/05/01 15:04:05  adam
  * Added ir-log command.
  *
  * Revision 1.99  1997/04/30 07:24:47  adam
@@ -497,8 +530,9 @@ int ir_tcl_eval (Tcl_Interp *interp, const char *command)
     r = Tcl_Eval (interp, tmp);
     if (r == TCL_ERROR)
     {
-        logf (LOG_WARN, "Tcl error in line %d: %s", interp->errorLine, 
-              interp->result);
+       const char *errorInfo = Tcl_GetVar (interp, "errorInfo", 0);
+        logf (LOG_WARN, "Tcl error in line %d: %s\n%s", interp->errorLine, 
+              interp->result, errorInfo ? errorInfo : "<null>");
     }
     Tcl_FreeResult (interp);
     xfree (tmp);
@@ -635,13 +669,14 @@ int ir_tcl_named_bits (struct ir_named_entry *tab, Odr_bitmask *ob,
         ODR_MASK_ZERO (ob);
         for (no = 0; no < argc; no++)
         {
+           int ok = 0;
             for (ti = tab; ti->name; ti++)
-                if (!strcmp (argv[no], ti->name))
+                if (!strcmp(argv[no], "@all") || !strcmp (argv[no], ti->name))
                 {
                     ODR_MASK_SET (ob, ti->pos);
-                    break;
+                    ok = 1;
                 }
-            if (!ti->name)
+            if (!ok)
             {
                 Tcl_AppendResult (interp, "bad bit mask ", argv[no], NULL);
                 return ir_tcl_error_exec (interp, argc, argv);
@@ -1170,24 +1205,12 @@ static int do_connect (void *obj, Tcl_Interp *interp,
         if (!strcmp (p->comstackType, "tcpip"))
         {
             p->cs_link = cs_create (tcpip_type, CS_BLOCK, p->protocol_type);
-            addr = tcpip_strtoaddr (argv[2]);
-            if (!addr)
-            {
-                Tcl_AppendResult (interp, "tcpip_strtoaddr fail", NULL);
-                return ir_tcl_error_exec (interp, argc, argv);
-            }
             logf (LOG_DEBUG, "tcp/ip connect %s", argv[2]);
         }
         else if (!strcmp (p->comstackType, "mosi"))
         {
 #if MOSI
             p->cs_link = cs_create (mosi_type, CS_BLOCK, p->protocol_type);
-            addr = mosi_strtoaddr (argv[2]);
-            if (!addr)
-            {
-                Tcl_AppendResult (interp, "mosi_strtoaddr fail", NULL);
-                return ir_tcl_error_exec (interp, argc, argv);
-            }
             logf (LOG_DEBUG, "mosi connect %s", argv[2]);
 #else
             Tcl_AppendResult (interp, "mosi not supported", NULL);
@@ -1203,6 +1226,13 @@ static int do_connect (void *obj, Tcl_Interp *interp,
         if (ir_tcl_strdup (interp, &p->hostname, argv[2]) == TCL_ERROR)
             return TCL_ERROR;
         p->eventType = "connect";
+       addr = cs_straddr (p->cs_link, argv[2]);
+       if (!addr)
+       {
+           ir_tcl_disconnect (p);
+           Tcl_AppendResult (interp, "cs_straddr fail", NULL);
+           return ir_tcl_error_exec (interp, argc, argv);
+       }
         if ((r=cs_connect (p->cs_link, addr)) < 0)
         {
             ir_tcl_disconnect (p);
@@ -1242,6 +1272,9 @@ void ir_tcl_disconnect (IrTcl_Obj *p)
 
         odr_reset (p->odr_in);
 
+#if TCL_MAJOR_VERSION == 8
+       cs_fileno(p->cs_link) = -1;
+#endif
         cs_close (p->cs_link);
         p->cs_link = NULL;
 
@@ -1832,7 +1865,7 @@ static int ir_obj_method (ClientData clientData, Tcl_Interp *interp,
                           int argc, char **argv)
 {
     IrTcl_Methods tab[3];
-    IrTcl_Obj *p = clientData;
+    IrTcl_Obj *p = (IrTcl_Obj *) clientData;
     int r;
 
     if (argc < 2)
@@ -1857,7 +1890,7 @@ static int ir_obj_method (ClientData clientData, Tcl_Interp *interp,
  */
 static void ir_obj_delete (ClientData clientData)
 {
-    IrTcl_Obj *obj = clientData;
+    IrTcl_Obj *obj = (IrTcl_Obj *) clientData;
     IrTcl_Methods tab[3];
 
     --(obj->ref_count);
@@ -1933,7 +1966,7 @@ int ir_obj_init (ClientData clientData, Tcl_Interp *interp,
         Tcl_AppendResult (interp, "Failed to initialize ", argv[1], NULL);
         return TCL_ERROR;
     }
-    *subData = obj;
+    *subData = (ClientData) obj;
     return TCL_OK;
 }
 
@@ -2517,7 +2550,7 @@ static int do_getSutrs (void *o, Tcl_Interp *interp, int argc, char **argv)
         Tcl_AppendResult (interp, "No DB record at #", argv[2], NULL);
         return TCL_ERROR;
     }
-    if (rl->u.dbrec.type != VAL_SUTRS)
+    if (!rl->u.dbrec.buf || rl->u.dbrec.type != VAL_SUTRS)
         return TCL_OK;
     Tcl_AppendElement (interp, rl->u.dbrec.buf);
     return TCL_OK;
@@ -2593,14 +2626,14 @@ static int do_getExplain (void *o, Tcl_Interp *interp, int argc, char **argv)
         Tcl_AppendResult (interp, "No DB record at #", argv[2], NULL);
         return TCL_ERROR;
     }
-    if (rl->u.dbrec.type != VAL_EXPLAIN)
+    if (!rl->u.dbrec.buf || rl->u.dbrec.type != VAL_EXPLAIN)
         return TCL_OK;
 
     if (!(etype = z_ext_getentbyref (VAL_EXPLAIN)))
         return TCL_OK;
-
+    assert (rl->u.dbrec.buf);
     odr_setbuf (p->odr_in, rl->u.dbrec.buf, rl->u.dbrec.size, 0);
-    if (!(*etype->fun)(p->odr_in, &rr, 0))
+    if (!(*etype->fun)(p->odr_in, (char **) &rr, 0))
         return TCL_OK;
     
     if (etype->what != Z_External_explainRecord)
@@ -2734,7 +2767,7 @@ static int do_present (void *o, Tcl_Interp *interp, int argc, char **argv)
 typedef struct {
     int encoding;
     int syntax;
-    int size;
+    size_t size;
 } IrTcl_FileRecordHead;
 
 /*
@@ -2919,7 +2952,7 @@ static int ir_set_obj_method (ClientData clientData, Tcl_Interp *interp,
                           int argc, char **argv)
 {
     IrTcl_Methods tabs[3];
-    IrTcl_SetObj *p = clientData;
+    IrTcl_SetObj *p = (IrTcl_SetObj *) clientData;
     int r;
 
     if (argc < 2)
@@ -2944,7 +2977,7 @@ static int ir_set_obj_method (ClientData clientData, Tcl_Interp *interp,
 static void ir_set_obj_delete (ClientData clientData)
 {
     IrTcl_Methods tabs[3];
-    IrTcl_SetObj *p = clientData;
+    IrTcl_SetObj *p = (IrTcl_SetObj *) clientData;
 
     logf (LOG_DEBUG, "ir set delete");
 
@@ -3044,7 +3077,7 @@ static int ir_set_obj_init (ClientData clientData, Tcl_Interp *interp,
     if (ir_tcl_method (interp, 0, NULL, tabs, NULL) == TCL_ERROR)
         return TCL_ERROR;
 
-    *subData = obj;
+    *subData = (ClientData) obj;
     return TCL_OK;
 }
 
@@ -3316,8 +3349,7 @@ static int do_scanLine (void *obj, Tcl_Interp *interp, int argc, char **argv)
     }
     if (Tcl_GetInt (interp, argv[2], &i) == TCL_ERROR)
         return TCL_ERROR;
-    if (!p->entries_flag || p->which != Z_ListEntries_entries || !p->entries
-        || i >= p->num_entries || i < 0)
+    if (!p->entries_flag || !p->entries || i >= p->num_entries || i < 0)
         return TCL_OK;
     switch (p->entries[i].which)
     {
@@ -3381,7 +3413,7 @@ static int ir_scan_obj_method (ClientData clientData, Tcl_Interp *interp,
 static void ir_scan_obj_delete (ClientData clientData)
 {
     IrTcl_Methods tabs[2];
-    IrTcl_ScanObj *obj = clientData;
+    IrTcl_ScanObj *obj = (IrTcl_ScanObj *) clientData;
 
     tabs[0].tab = ir_scan_method_tab;
     tabs[0].obj = obj;
@@ -3464,7 +3496,19 @@ static int ir_log_proc (ClientData clientData, Tcl_Interp *interp,
         return TCL_OK;
     }
     mask = log_mask_str_x (argv[1], 0);
-    logf (mask, "%s", argv[1], mask, argv[2]);
+    logf (LOG_DEBUG, "%s", argv[2]);
+    return TCL_OK;
+}
+
+
+/* 
+ * ir_version: log ir version
+ */
+static int ir_version (ClientData clientData, Tcl_Interp *interp,
+                        int argc, char **argv)
+{
+    Tcl_AppendElement (interp, IR_TCL_VERSION);
+    Tcl_AppendElement (interp, YAZ_VERSION);
     return TCL_OK;
 }
 
@@ -3532,7 +3576,7 @@ static void ir_handleDiags (IrTcl_Diagnostic **dst_list, int *dst_num,
                             Z_DiagRec **list, int num)
 {
     int i;
-    char *addinfo;
+    char *addinfo = NULL;
 
     *dst_num = num;
     *dst_list = ir_tcl_malloc (sizeof(**dst_list) * num);
@@ -3543,7 +3587,19 @@ static void ir_handleDiags (IrTcl_Diagnostic **dst_list, int *dst_num,
         {
         case Z_DiagRec_defaultFormat:
             (*dst_list)[i].condition = *list[i]->u.defaultFormat->condition;
+#ifdef ASN_COMPILED
+           switch (list[i]->u.defaultFormat->which)
+           {
+           case Z_DefaultDiagFormat_v2Addinfo:
+               addinfo = list[i]->u.defaultFormat->u.v2Addinfo;
+               break;
+           case Z_DefaultDiagFormat_v3Addinfo:
+               addinfo = list[i]->u.defaultFormat->u.v3Addinfo;
+               break;
+           }
+#else
             addinfo = list[i]->u.defaultFormat->addinfo;
+#endif
             if (addinfo && 
                 ((*dst_list)[i].addinfo = ir_tcl_malloc (strlen(addinfo)+1)))
                 strcpy ((*dst_list)[i].addinfo, addinfo);
@@ -3563,7 +3619,8 @@ static void ir_handleDBRecord (IrTcl_Obj *p, IrTcl_RecordList *rl,
 {
     struct oident *ident;
     Z_ext_typeent *etype;
-                
+
+    logf (LOG_DEBUG, "handleDBRecord size=%d", oe->u.octet_aligned->len);
     rl->u.dbrec.size = oe->u.octet_aligned->len;
     rl->u.dbrec.buf = NULL;
     
@@ -3580,8 +3637,11 @@ static void ir_handleDBRecord (IrTcl_Obj *p, IrTcl_RecordList *rl,
         
         odr_setbuf (p->odr_in, (char*) oe->u.octet_aligned->buf,
                     oe->u.octet_aligned->len, 0);
-        if (!(*etype->fun)(p->odr_in, &rr, 0))
+        if (!(*etype->fun)(p->odr_in, (char **) &rr, 0))
+        {
+            rl->u.dbrec.type = VAL_NONE;
             return;
+        }
         switch (etype->what)
         {
         case Z_External_sutrs:
@@ -3652,10 +3712,16 @@ static void ir_handleZRecords (void *o, Z_Records *zrs, IrTcl_SetObj *setobj,
                     &setobj->nonSurrogateDiagnosticNum);
     if (zrs->which == Z_Records_DBOSD)
     {
-        setobj->numberOfRecordsReturned = 
-            zrs->u.databaseOrSurDiagnostics->num_records;
-        logf (LOG_DEBUG, "Got %d records", setobj->numberOfRecordsReturned);
-        for (offset = 0; offset < setobj->numberOfRecordsReturned; offset++)
+       int num_rec = zrs->u.databaseOrSurDiagnostics->num_records;
+
+        if (num_rec != setobj->numberOfRecordsReturned)
+        {
+           logf (LOG_WARN, "numberOfRecordsReturned=%d but num records=%d",
+                       setobj->numberOfRecordsReturned, num_rec);
+            setobj->numberOfRecordsReturned = num_rec;
+        }
+
+        for (offset = 0; offset < num_rec; offset++)
         {
             Z_NamePlusRecord *znpr = zrs->u.databaseOrSurDiagnostics->
                 records[offset];
@@ -3684,12 +3750,19 @@ static void ir_handleZRecords (void *o, Z_Records *zrs, IrTcl_SetObj *setobj,
     }
     else
     {
+#ifdef ASN_COMPILED
+        Z_DiagRec dr, *dr_p = &dr;
+        dr.which = Z_DiagRec_defaultFormat;
+        dr.u.defaultFormat = zrs->u.nonSurrogateDiagnostic;
+#else
+        Z_DiagRec *dr_p = zrs->u.nonSurrogateDiagnostic;
+#endif
         logf (LOG_DEBUG, "NonSurrogateDiagnostic");
+
         setobj->numberOfRecordsReturned = 0;
         ir_handleDiags (&setobj->nonSurrogateDiagnosticList,
                         &setobj->nonSurrogateDiagnosticNum,
-                        &zrs->u.nonSurrogateDiagnostic,
-                        1);
+                        &dr_p, 1);
     }
 }
 
@@ -3704,11 +3777,13 @@ static void ir_searchResponse (void *o, Z_SearchResponse *searchrs,
         logf (LOG_DEBUG, "Search response, no object!");
         return;
     }
-    setobj->searchStatus = searchrs->searchStatus ? 1 : 0;
+    setobj->searchStatus = *searchrs->searchStatus;
     get_referenceId (&setobj->set_inher.referenceId, searchrs->referenceId);
     setobj->resultCount = *searchrs->resultCount;
     if (searchrs->presentStatus)
         setobj->presentStatus = *searchrs->presentStatus;
+    else
+        setobj->presentStatus = Z_RES_NONE;
     if (searchrs->nextResultSetPosition)
         setobj->nextResultSetPosition = *searchrs->nextResultSetPosition;
 
@@ -3721,10 +3796,14 @@ static void ir_searchResponse (void *o, Z_SearchResponse *searchrs,
             es = setobj->set_inher.smallSetElementSetNames;
         else 
             es = setobj->set_inher.mediumSetElementSetNames;
+       setobj->numberOfRecordsReturned = *searchrs->numberOfRecordsReturned;
         ir_handleZRecords (o, zrs, setobj, es);
     }
     else
+    {
+       setobj->numberOfRecordsReturned = 0;
         setobj->recordFlag = 0;
+    }
 }
 
 
@@ -3743,9 +3822,13 @@ static void ir_presentResponse (void *o, Z_PresentResponse *presrs,
     get_referenceId (&setobj->set_inher.referenceId, presrs->referenceId);
     setobj->nextResultSetPosition = *presrs->nextResultSetPosition;
     if (zrs)
+    {
+       setobj->numberOfRecordsReturned = *presrs->numberOfRecordsReturned;
         ir_handleZRecords (o, zrs, setobj, setobj->set_inher.elementSetNames);
+    }
     else
     {
+       setobj->numberOfRecordsReturned = 0;
         setobj->recordFlag = 0;
         logf (LOG_DEBUG, "No records!");
     }
@@ -3778,67 +3861,61 @@ static void ir_scanResponse (void *o, Z_ScanResponse *scanrs,
 
     xfree (scanobj->entries);
     scanobj->entries = NULL;
-
+    scanobj->num_entries = 0;
+    scanobj->entries_flag = 0;
+       
     ir_deleteDiags (&scanobj->nonSurrogateDiagnosticList,
                     &scanobj->nonSurrogateDiagnosticNum);
     if (scanrs->entries)
     {
         int i;
-        Z_Entry *ze;
+        Z_Entry **ze;
 
         scanobj->entries_flag = 1;
-        scanobj->which = scanrs->entries->which;
-        switch (scanobj->which)
-        {
-        case Z_ListEntries_entries:
-            scanobj->num_entries = scanrs->entries->u.entries->num_entries;
+       if (scanrs->entries)
+       {
+            scanobj->num_entries = scanrs->entries->num_entries;
             scanobj->entries = ir_tcl_malloc (scanobj->num_entries * 
-                                       sizeof(*scanobj->entries));
-            for (i=0; i<scanobj->num_entries; i++)
-            {
-                ze = scanrs->entries->u.entries->entries[i];
-                scanobj->entries[i].which = ze->which;
-                switch (ze->which)
-                {
-                case Z_Entry_termInfo:
-                    if (ze->u.termInfo->term->which == Z_Term_general)
-                    {
-                        int l = ze->u.termInfo->term->u.general->len;
-                        scanobj->entries[i].u.term.buf = ir_tcl_malloc (1+l);
-                        memcpy (scanobj->entries[i].u.term.buf, 
-                                ze->u.termInfo->term->u.general->buf,
-                                l);
-                        scanobj->entries[i].u.term.buf[l] = '\0';
-                    }
-                    else
-                        scanobj->entries[i].u.term.buf = NULL;
-                    if (ze->u.termInfo->globalOccurrences)
-                        scanobj->entries[i].u.term.globalOccurrences = 
-                            *ze->u.termInfo->globalOccurrences;
-                    else
-                        scanobj->entries[i].u.term.globalOccurrences = 0;
-                    break;
-                case Z_Entry_surrogateDiagnostic:
-                    ir_handleDiags (&scanobj->entries[i].u.diag.list,
-                                    &scanobj->entries[i].u.diag.num,
-                                    &ze->u.surrogateDiagnostic,
-                                    1);
-                    break;
-                }
-            }
-            break;
-        case Z_ListEntries_nonSurrogateDiagnostics:
-            ir_handleDiags (&scanobj->nonSurrogateDiagnosticList,
+                                             sizeof(*scanobj->entries));
+           ze = scanrs->entries->entries;
+       }
+       for (i=0; i<scanobj->num_entries; i++, ze++)
+       {
+           scanobj->entries[i].which = (*ze)->which;
+           switch ((*ze)->which)
+           {
+           case Z_Entry_termInfo:
+               if ((*ze)->u.termInfo->term->which == Z_Term_general)
+               {
+                   int l = (*ze)->u.termInfo->term->u.general->len;
+                   scanobj->entries[i].u.term.buf = ir_tcl_malloc (1+l);
+                   memcpy (scanobj->entries[i].u.term.buf, 
+                           (*ze)->u.termInfo->term->u.general->buf,
+                           l);
+                   scanobj->entries[i].u.term.buf[l] = '\0';
+               }
+               else
+                   scanobj->entries[i].u.term.buf = NULL;
+               if ((*ze)->u.termInfo->globalOccurrences)
+                   scanobj->entries[i].u.term.globalOccurrences = 
+                       *(*ze)->u.termInfo->globalOccurrences;
+               else
+                   scanobj->entries[i].u.term.globalOccurrences = 0;
+               break;
+           case Z_Entry_surrogateDiagnostic:
+               ir_handleDiags (&scanobj->entries[i].u.diag.list,
+                               &scanobj->entries[i].u.diag.num,
+                               &(*ze)->u.surrogateDiagnostic,
+                               1);
+               break;
+           }
+       }
+       if (scanrs->entries->nonsurrogateDiagnostics)
+           ir_handleDiags (&scanobj->nonSurrogateDiagnosticList,
                             &scanobj->nonSurrogateDiagnosticNum,
-                            scanrs->entries->u.nonSurrogateDiagnostics->
-                            diagRecs,
-                            scanrs->entries->u.nonSurrogateDiagnostics->
-                            num_diagRecs);
-            break;
-        }
+                            scanrs->entries->nonsurrogateDiagnostics,
+                            scanrs->entries->num_nonsurrogateDiagnostics);
     }
-    else
-        scanobj->entries_flag = 0;
 }
 
 /*
@@ -3846,7 +3923,7 @@ static void ir_scanResponse (void *o, Z_ScanResponse *scanrs,
  */
 static void ir_select_read (ClientData clientData)
 {
-    IrTcl_Obj *p = clientData;
+    IrTcl_Obj *p = (IrTcl_Obj *) clientData;
     Z_APDU *apdu;
     int r;
     IrTcl_Request *rq;
@@ -3876,7 +3953,7 @@ static void ir_select_read (ClientData clientData)
                 p->failInfo = IR_TCL_FAIL_CONNECT;
                 ir_tcl_eval (p->interp, p->failback);
             }
-            ir_obj_delete (p);
+            ir_obj_delete ((ClientData) p);
             return;
         }
         if (p->callback)
@@ -3884,7 +3961,7 @@ static void ir_select_read (ClientData clientData)
         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);
+        ir_obj_delete ((ClientData) p);
         return;
     }
     do
@@ -3903,7 +3980,6 @@ static void ir_select_read (ClientData clientData)
         if (r <= 0)
         {
             logf (LOG_DEBUG, "cs_get failed, code %d", r);
-            ir_select_remove (cs_fileno (p->cs_link), p);
             ir_tcl_disconnect (p);
             if (p->failback)
             {
@@ -3911,7 +3987,7 @@ static void ir_select_read (ClientData clientData)
                 ir_tcl_eval (p->interp, p->failback);
             }
             /* release ir object now if callback deleted it */
-            ir_obj_delete (p);
+            ir_obj_delete ((ClientData) p);
             return;
         }        
         /* got complete APDU. Now decode */
@@ -3931,7 +4007,7 @@ static void ir_select_read (ClientData clientData)
                 ir_tcl_eval (p->interp, p->failback);
             }
             /* release ir object now if failback deleted it */
-            ir_obj_delete (p);
+            ir_obj_delete ((ClientData) p);
             return;
         }
         /* handle APDU and invoke callback */
@@ -4000,10 +4076,10 @@ static void ir_select_read (ClientData clientData)
         odr_reset (p->odr_in);
         if (p->ref_count == 1)
         {
-            ir_obj_delete (p);
+            ir_obj_delete ((ClientData) p);
             return;
         }
-        ir_obj_delete (p);
+        ir_obj_delete ((ClientData) 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");
@@ -4014,7 +4090,7 @@ static void ir_select_read (ClientData clientData)
  */
 static int ir_select_write (ClientData clientData)
 {
-    IrTcl_Obj *p = clientData;
+    IrTcl_Obj *p = (IrTcl_Obj *) clientData;
     int r;
     IrTcl_Request *rq;
 
@@ -4040,12 +4116,12 @@ static int ir_select_write (ClientData clientData)
                 p->failInfo = IR_TCL_FAIL_CONNECT;
                 ir_tcl_eval (p->interp, p->failback);
             }
-            ir_obj_delete (p);
+            ir_obj_delete ((ClientData) p);
             return 2;
         }
         if (p->callback)
             ir_tcl_eval (p->interp, p->callback);
-        ir_obj_delete (p);
+        ir_obj_delete ((ClientData) p);
         return 2;
     }
     rq = p->request_queue;
@@ -4064,7 +4140,7 @@ static int ir_select_write (ClientData clientData)
             p->failInfo = IR_TCL_FAIL_WRITE;
             ir_tcl_eval (p->interp, p->failback);
         }
-        ir_obj_delete (p);
+        ir_obj_delete ((ClientData) p);
     }
     else if (r == 0)            /* remove select bit */
     {
@@ -4133,6 +4209,9 @@ EXPORT (int,Irtcl_Init) (Tcl_Interp *interp)
                        (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
     Tcl_CreateCommand (interp, "ir-log", ir_log_proc,
                        (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
+    Tcl_CreateCommand (interp, "ir-version", ir_version, (ClientData) NULL,
+                       (Tcl_CmdDeleteProc *) NULL);
+    nmem_init ();
     return TCL_OK;
 }