X-Git-Url: http://git.indexdata.com/?a=blobdiff_plain;f=ir-tcl.c;h=9b4ee5c20e39476407ab2f9d8f96457f6f809ebb;hb=d026c3e06f6e19e5ed4174ab1a504a4b5af79183;hp=4650a77297ff600d48e1e622d74a1013822ea09d;hpb=f74154d3c256f1147dfc5de059cf50ba2c4f0280;p=ir-tcl-moved-to-github.git diff --git a/ir-tcl.c b/ir-tcl.c index 4650a77..9b4ee5c 100644 --- a/ir-tcl.c +++ b/ir-tcl.c @@ -1,11 +1,101 @@ /* * IR toolkit for tcl/tk - * (c) Index Data 1995-1996 + * (c) Index Data 1995-2003 * See the file LICENSE for details. - * Sebastian Hammer, Adam Dickmeiss * * $Log: ir-tcl.c,v $ - * Revision 1.99 1997-04-30 07:24:47 adam + * Revision 1.128 2005-03-10 13:54:56 adam + * Remove CCL support for scan + * + * Revision 1.127 2004/05/10 08:38:45 adam + * Do not use obsolete YAZ defines + * + * Revision 1.126 2003/11/29 17:24:09 adam + * Added getXml method (Franck Falcoz) + * + * Revision 1.125 2003/04/29 10:51:23 adam + * Null terminate octet aligned records + * + * Revision 1.124 2003/03/05 22:02:47 adam + * Add Tcl_InitStubs + * + * Revision 1.123 2003/03/05 21:21:41 adam + * APDU log. default largeSetLowerBound changed from 2 to 1 + * + * Revision 1.122 2003/03/05 18:02:08 adam + * Fix bug with idAuthentication that didn't work for empty group. + * + * Revision 1.121 2003/01/30 13:27:07 adam + * Changed version to 1.4.1. Added WIN32 version resource. + * IrTcl ignores unexpected PDU's, rather than die. + * + * Revision 1.120 2002/03/20 14:48:54 adam + * implemented USR.1 SearchResult-1 + * + * Revision 1.119 2001/12/03 00:31:06 adam + * Towards 1.4. Configure updates. + * + * Revision 1.118 2001/03/27 16:27:21 adam + * Fixed bug in do_responseStatus. + * + * Revision 1.117 2001/03/26 11:39:34 adam + * Fixed bug in ir_deleteDiags - crash when receiving multiple diags. + * + * Revision 1.116 2001/02/09 11:58:04 adam + * Updated for Tcl8.1 and higher where internal encoding is UTF-8. + * + * Revision 1.115 2000/09/13 12:18:49 adam + * Logging utility patch (YAZ version 1.7). + * + * Revision 1.114 1999/05/17 20:37:41 adam + * Fixed problem with ASN code. + * + * Revision 1.113 1999/04/20 10:01:46 adam + * Modified calls to ODR encoders/decoders (name argument). + * + * Revision 1.112 1999/03/22 06:51:34 adam + * Implemented sort. + * + * Revision 1.111 1999/02/11 11:30:09 adam + * Updated for WIN32. + * + * 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 * Spell fix of an error message. * * Revision 1.98 1997/04/13 18:57:20 adam @@ -355,7 +445,7 @@ #include #include -#ifdef WINDOWS +#ifdef WIN32 #else #include @@ -392,6 +482,7 @@ #endif static char *wrongArgs = "wrong # args: should be \""; +static FILE *odr_print_file = 0; static int ir_tcl_error_exec (Tcl_Interp *interp, int argc, char **argv) { @@ -452,6 +543,17 @@ static void delete_IR_record (IrTcl_RecordList *rl) xfree (rl->elements); } +static void purge_IR_records (IrTcl_SetObj *setobj) +{ + IrTcl_RecordList *rl; + while ((rl = setobj->record_list)) + { + setobj->record_list = rl->next; + delete_IR_record (rl); + xfree (rl); + } +} + static IrTcl_RecordList *new_IR_record (IrTcl_SetObj *setobj, int no, int which, const char *elements) @@ -494,8 +596,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 : ""); } Tcl_FreeResult (interp); xfree (tmp); @@ -632,13 +735,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); @@ -707,7 +811,7 @@ static int do_init_request (void *obj, Tcl_Interp *interp, req->preferredMessageSize = &p->preferredMessageSize; req->maximumRecordSize = &p->maximumRecordSize; - if (p->idAuthenticationGroupId) + if (p->idAuthenticationGroupId || p->idAuthenticationUserId) { Z_IdPass *pass = odr_malloc (p->odr_out, sizeof(*pass)); Z_IdAuthentication *auth = odr_malloc (p->odr_out, sizeof(*auth)); @@ -730,9 +834,7 @@ static int do_init_request (void *obj, Tcl_Interp *interp, pass->password = NULL; req->idAuthentication = auth; } - else if (!p->idAuthenticationOpen || !*p->idAuthenticationOpen) - req->idAuthentication = NULL; - else + else if (p->idAuthenticationOpen && *p->idAuthenticationOpen) { Z_IdAuthentication *auth = odr_malloc (p->odr_out, sizeof(*auth)); @@ -741,6 +843,8 @@ static int do_init_request (void *obj, Tcl_Interp *interp, auth->u.open = p->idAuthenticationOpen; req->idAuthentication = auth; } + else + req->idAuthentication = NULL; req->implementationId = p->implementationId; req->implementationName = p->implementationName; req->implementationVersion = p->implementationVersion; @@ -966,7 +1070,7 @@ static int do_implementationName (void *obj, Tcl_Interp *interp, if (argc == 0) return ir_tcl_strdup (interp, &p->implementationName, - "Index Data/IrTcl on YAZ"); + "IrTcl/YAZ"); else if (argc == -1) return ir_tcl_strdel (interp, &p->implementationName); if (argc == 3) @@ -989,7 +1093,7 @@ static int do_implementationId (void *obj, Tcl_Interp *interp, IrTcl_Obj *p = obj; if (argc == 0) - return ir_tcl_strdup (interp, &p->implementationId, "YAZ (id=81)"); + return ir_tcl_strdup (interp, &p->implementationId, "81"); else if (argc == -1) return ir_tcl_strdel (interp, &p->implementationId); Tcl_AppendResult (interp, p->implementationId, (char*) NULL); @@ -1006,10 +1110,10 @@ static int do_implementationVersion (void *obj, Tcl_Interp *interp, if (argc == 0) return ir_tcl_strdup (interp, &p->implementationVersion, - "YAZ: " YAZ_VERSION #ifdef IR_TCL_VERSION - " / Irtcl: " IR_TCL_VERSION + IR_TCL_VERSION "/" #endif + YAZ_VERSION ); else if (argc == -1) return ir_tcl_strdel (interp, &p->implementationVersion); @@ -1102,6 +1206,12 @@ static int do_idAuthentication (void *obj, Tcl_Interp *interp, { if (argc == 3) { + xfree (p->idAuthenticationGroupId); + xfree (p->idAuthenticationUserId); + xfree (p->idAuthenticationPassword); + p->idAuthenticationGroupId = NULL; + p->idAuthenticationUserId = NULL; + p->idAuthenticationPassword = NULL; if (argv[2][0] && ir_tcl_strdup (interp, &p->idAuthenticationOpen, argv[2]) == TCL_ERROR) @@ -1109,6 +1219,8 @@ static int do_idAuthentication (void *obj, Tcl_Interp *interp, } else if (argc == 5) { + xfree (p->idAuthenticationOpen); + p->idAuthenticationOpen = NULL; if (argv[2][0] && ir_tcl_strdup (interp, &p->idAuthenticationGroupId, argv[2]) == TCL_ERROR) @@ -1125,7 +1237,7 @@ static int do_idAuthentication (void *obj, Tcl_Interp *interp, } if (p->idAuthenticationOpen) Tcl_AppendElement (interp, p->idAuthenticationOpen); - else if (p->idAuthenticationGroupId) + else if (p->idAuthenticationGroupId || p->idAuthenticationUserId) { Tcl_AppendElement (interp, p->idAuthenticationGroupId); Tcl_AppendElement (interp, p->idAuthenticationUserId); @@ -1167,24 +1279,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); @@ -1200,6 +1300,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); @@ -1239,6 +1346,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; @@ -1308,11 +1418,11 @@ static int do_logLevel (void *o, Tcl_Interp *interp, if (argc <= 2) return TCL_OK; if (argc == 3) - log_init (log_mask_str (argv[2]), "", NULL); + yaz_log_init (yaz_log_mask_str (argv[2]), "", NULL); else if (argc == 4) - log_init (log_mask_str (argv[2]), argv[3], NULL); + yaz_log_init (yaz_log_mask_str (argv[2]), argv[3], NULL); else if (argc == 5) - log_init (log_mask_str (argv[2]), argv[3], argv[4]); + yaz_log_init (yaz_log_mask_str (argv[2]), argv[3], argv[4]); return TCL_OK; } @@ -1478,7 +1588,7 @@ static int do_triggerResourceControl (void *obj, Tcl_Interp *interp, } apdu = zget_APDU (p->odr_out, Z_APDU_triggerResourceControlRequest); req = apdu->u.triggerResourceControlRequest; - *req->requestedAction = Z_TriggerResourceCtrl_cancel; + *req->requestedAction = Z_TriggerResourceControlRequest_cancel; req->resultSetWanted = &is_false; return ir_tcl_send_APDU (interp, p, apdu, "triggerResourceControl", @@ -1614,7 +1724,7 @@ static int do_largeSetLowerBound (void *o, Tcl_Interp *interp, if (argc <= 0) { - p->largeSetLowerBound = 2; + p->largeSetLowerBound = 1; return TCL_OK; } return ir_tcl_get_set_int (&p->largeSetLowerBound, interp, argc, argv); @@ -1829,7 +1939,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) @@ -1854,7 +1964,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); @@ -1874,7 +1984,11 @@ static void ir_obj_delete (ClientData clientData) ir_tcl_del_q (obj); odr_destroy (obj->odr_in); odr_destroy (obj->odr_out); - odr_destroy (obj->odr_pr); + if (obj->odr_pr) + { + obj->odr_pr->print = 0; + odr_destroy (obj->odr_pr); + } xfree (obj); } @@ -1911,7 +2025,12 @@ int ir_obj_init (ClientData clientData, Tcl_Interp *interp, obj->odr_in = odr_createmem (ODR_DECODE); odr_choice_enable_bias (obj->odr_in, 0); obj->odr_out = odr_createmem (ODR_ENCODE); - obj->odr_pr = odr_createmem (ODR_PRINT); + obj->odr_pr = 0; + if (odr_print_file) + { + obj->odr_pr = odr_createmem (ODR_PRINT); + odr_setprint(obj->odr_pr, odr_print_file); + } obj->state = IR_TCL_R_Idle; obj->interp = interp; @@ -1930,7 +2049,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; } @@ -1971,7 +2090,11 @@ static int do_search (void *o, Tcl_Interp *interp, int argc, char **argv) Odr_oct ccl_query; IrTcl_SetObj *obj = o; IrTcl_Obj *p; - int r; + int r, code; +#if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION > 0) + Tcl_DString ds; +#endif + char *query_str; if (argc <= 0) return TCL_OK; @@ -1984,16 +2107,23 @@ static int do_search (void *o, Tcl_Interp *interp, int argc, char **argv) NULL); return TCL_ERROR; } - logf (LOG_DEBUG, "search %s %s", *argv, argv[2]); +#if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION > 0) + query_str = Tcl_UtfToExternalDString(0, argv[2], -1, &ds); +#else + query_str = argv[2]; +#endif + logf (LOG_DEBUG, "search %s %s", *argv, query_str); if (!obj->set_inher.num_databaseNames) { Tcl_AppendResult (interp, "no databaseNames", NULL); - return ir_tcl_error_exec (interp, argc, argv); + code = ir_tcl_error_exec (interp, argc, argv); + goto out; } if (!p->cs_link) { Tcl_AppendResult (interp, "not connected", NULL); - return ir_tcl_error_exec (interp, argc, argv); + code = ir_tcl_error_exec (interp, argc, argv); + goto out; } apdu = zget_APDU (p->odr_out, Z_APDU_searchRequest); req = apdu->u.searchRequest; @@ -2058,11 +2188,12 @@ static int do_search (void *o, Tcl_Interp *interp, int argc, char **argv) { Z_RPNQuery *RPNquery; - RPNquery = p_query_rpn (p->odr_out, p->protocol_type, argv[2]); + RPNquery = p_query_rpn (p->odr_out, p->protocol_type, query_str); if (!RPNquery) { Tcl_AppendResult (interp, "query syntax error", NULL); - return ir_tcl_error_exec (interp, argc, argv); + code = ir_tcl_error_exec (interp, argc, argv); + goto out; } query.which = Z_Query_type_1; query.u.type_1 = RPNquery; @@ -2080,18 +2211,19 @@ static int do_search (void *o, Tcl_Interp *interp, int argc, char **argv) bib1.oclass = CLASS_ATTSET; bib1.value = VAL_BIB1; - rpn = ccl_find_str(p->bibset, argv[2], &error, &pos); + rpn = ccl_find_str(p->bibset, query_str, &error, &pos); if (error) { Tcl_AppendResult (interp, "ccl syntax error ", ccl_err_msg(error), NULL); - return ir_tcl_error_exec (interp, argc, argv); + code = ir_tcl_error_exec (interp, argc, argv); + goto out; } #if 0 ccl_pr_tree (rpn, stderr); fprintf (stderr, "\n"); #endif - assert((RPNquery = ccl_rpn_query(rpn))); + RPNquery = ccl_rpn_query(p->odr_out, rpn); RPNquery->attributeSetId = oid_getoidbyent (&bib1); query.which = Z_Query_type_1; query.u.type_1 = RPNquery; @@ -2101,16 +2233,22 @@ static int do_search (void *o, Tcl_Interp *interp, int argc, char **argv) { query.which = Z_Query_type_2; query.u.type_2 = &ccl_query; - ccl_query.buf = (unsigned char *) argv[2]; - ccl_query.len = strlen (argv[2]); + ccl_query.buf = (unsigned char *) query_str; + ccl_query.len = strlen (query_str); } else { Tcl_AppendResult (interp, "invalid query method ", obj->set_inher.queryType, NULL); - return ir_tcl_error_exec (interp, argc, argv); + code = ir_tcl_error_exec (interp, argc, argv); + goto out; } - return ir_tcl_send_APDU (interp, p, apdu, "search", *argv); + code = ir_tcl_send_APDU (interp, p, apdu, "search", *argv); + out: +#if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION > 0) + Tcl_DStringFree (&ds); +#endif + return code; } /* @@ -2174,6 +2312,36 @@ static int do_presentResponse (void *o, Tcl_Interp *interp, } /* + * do_sortResponse: add sort response handler + */ +static int do_sortResponse (void *o, Tcl_Interp *interp, + int argc, char **argv) +{ + IrTcl_SetObj *obj = o; + + if (argc == 0) + { + obj->sortResponse = NULL; + return TCL_OK; + } + else if (argc == -1) + return ir_tcl_strdel (interp, &obj->sortResponse); + if (argc == 3) + { + xfree (obj->sortResponse); + if (argv[2][0]) + { + if (ir_tcl_strdup (interp, &obj->sortResponse, argv[2]) + == TCL_ERROR) + return TCL_ERROR; + } + else + obj->sortResponse = NULL; + } + return TCL_OK; +} + +/* * do_resultCount: Get number of hits */ static int do_resultCount (void *o, Tcl_Interp *interp, @@ -2202,6 +2370,54 @@ static int do_searchStatus (void *o, Tcl_Interp *interp, return ir_tcl_get_set_int (&obj->searchStatus, interp, argc, argv); } +static void reset_searchResult (IrTcl_SetObj *setobj) +{ + int i; + for (i = 0; isearchResult_num; i++) + xfree (setobj->searchResult_terms[i]); + xfree (setobj->searchResult_terms); + xfree (setobj->searchResult_count); + setobj->searchResult_terms = 0; + setobj->searchResult_num = 0; +} + + +/* + * do_searchResult Get USR:Search-Result1 (after search response) + */ +static int do_searchResult (void *o, Tcl_Interp *interp, + int argc, char **argv) +{ + IrTcl_SetObj *obj = o; + int i; + + if (argc == 0) + { + obj->searchResult_num = 0; + obj->searchResult_terms = 0; + obj->searchResult_count = 0; + return TCL_OK; + } + else if (argc == -1) + { + reset_searchResult (obj); + return TCL_OK; + } + for (i = 0; isearchResult_num; i++) + { + char str[40]; + sprintf (str, "%d", obj->searchResult_count[i]); + Tcl_AppendResult (interp, "{", NULL); + if (obj->searchResult_terms[i]) + Tcl_AppendElement (interp, obj->searchResult_terms[i]); + else + Tcl_AppendElement (interp, ""); + Tcl_AppendElement (interp, str); + Tcl_AppendResult (interp, "} ", NULL); + } + return TCL_OK; +} + /* * do_presentStatus: Get search status (after search/present response) */ @@ -2216,6 +2432,35 @@ static int do_presentStatus (void *o, Tcl_Interp *interp, } /* + * do_sortStatus: Get sort status (after sort response) + */ +static int do_sortStatus (void *o, Tcl_Interp *interp, + int argc, char **argv) +{ + IrTcl_SetObj *obj = o; + char *res; + + if (argc <= 0) + { + obj->sortStatus = Z_SortResponse_failure; + return TCL_OK; + } + switch (obj->sortStatus) + { + case Z_SortResponse_success: + res = "success"; break; + case Z_SortResponse_partial_1: + res = "partial"; break; + case Z_SortResponse_failure: + res = "failure"; break; + default: + res = "unknown"; break; + } + Tcl_AppendElement (interp, res); + return TCL_OK; +} + +/* * do_nextResultSetPosition: Get next result set position * (after search/present response) */ @@ -2514,12 +2759,47 @@ 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; } +/* + * do_getXml: Get XML Record + */ +static int do_getXml (void *o, Tcl_Interp *interp, int argc, char **argv) +{ + IrTcl_SetObj *obj = o; + int offset; + IrTcl_RecordList *rl; + + if (argc <= 0) + return TCL_OK; + if (argc != 3) + { + Tcl_AppendResult (interp, wrongArgs, *argv, " ", argv[1], + " position\"", NULL); + return TCL_ERROR; + } + if (Tcl_GetInt (interp, argv[2], &offset)==TCL_ERROR) + return TCL_ERROR; + rl = find_IR_record (obj, offset); + if (!rl) + { + Tcl_AppendResult (interp, "No record at #", argv[2], NULL); + return TCL_ERROR; + } + if (rl->which != Z_NamePlusRecord_databaseRecord) + { + Tcl_AppendResult (interp, "No DB record at #", argv[2], NULL); + return TCL_ERROR; + } + if (!rl->u.dbrec.buf || rl->u.dbrec.type != VAL_TEXT_XML) + return TCL_OK; + Tcl_AppendElement (interp, rl->u.dbrec.buf); + return TCL_OK; +} /* * do_getGrs: Get a GRS-1 Record @@ -2590,14 +2870,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, 0)) return TCL_OK; if (etype->what != Z_External_explainRecord) @@ -2641,6 +2921,10 @@ static int do_responseStatus (void *o, Tcl_Interp *interp, Tcl_AppendElement (interp, "NSD"); return ir_diagResult (interp, obj->nonSurrogateDiagnosticList, obj->nonSurrogateDiagnosticNum); + case Z_Records_multipleNSD: + Tcl_AppendElement (interp, "NSD"); + return ir_diagResult (interp, obj->nonSurrogateDiagnosticList, + obj->nonSurrogateDiagnosticNum); } return TCL_OK; } @@ -2731,7 +3015,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; /* @@ -2884,6 +3168,171 @@ static int do_saveFile (void *o, Tcl_Interp *interp, } +/* ------------------------------------------------------- */ +/* + * do_sort: Do sort request + */ +static int do_sort (void *o, Tcl_Interp *interp, int argc, char **argv) +{ + Z_SortRequest *req; + Z_APDU *apdu; + IrTcl_SetObj *obj = o; + IrTcl_Obj *p; + char sort_string[64], sort_flags[64]; + char *arg; + int off; + Z_SortKeySpecList *sksl; + int oid[OID_SIZE]; + oident bib1; + + if (argc <= 0) + return TCL_OK; + + p = obj->parent; + assert (argc > 1); + if (argc != 3) + { + Tcl_AppendResult (interp, wrongArgs, *argv, " ", argv[1], "query\"", + NULL); + return TCL_ERROR; + } + logf (LOG_DEBUG, "sort %s %s", *argv, argv[2]); + if (!p->cs_link) + { + Tcl_AppendResult (interp, "not connected", NULL); + return ir_tcl_error_exec (interp, argc, argv); + } + apdu = zget_APDU (p->odr_out, Z_APDU_sortRequest); + sksl = (Z_SortKeySpecList *) odr_malloc (p->odr_out, sizeof(*sksl)); + req = apdu->u.sortRequest; + + set_referenceId (p->odr_out, &req->referenceId, + obj->set_inher.referenceId); + +#ifdef ASN_COMPILED + req->num_inputResultSetNames = 1; + req->inputResultSetNames = (Z_InternationalString **) + odr_malloc (p->odr_out, sizeof(*req->inputResultSetNames)); + req->inputResultSetNames[0] = obj->setName; +#else + req->inputResultSetNames = + (Z_StringList *)odr_malloc (p->odr_out, + sizeof(*req->inputResultSetNames)); + req->inputResultSetNames->num_strings = 1; + req->inputResultSetNames->strings = + (char **)odr_malloc (p->odr_out, + sizeof(*req->inputResultSetNames->strings)); + req->inputResultSetNames->strings[0] = obj->setName; +#endif + + req->sortedResultSetName = (char *) obj->setName; + + + req->sortSequence = sksl; + sksl->num_specs = 0; + sksl->specs = (Z_SortKeySpec **) + odr_malloc (p->odr_out, sizeof(sksl->specs) * 20); + + bib1.proto = PROTO_Z3950; + bib1.oclass = CLASS_ATTSET; + bib1.value = VAL_BIB1; + arg = argv[2]; + while ((sscanf (arg, "%63s %63s%n", sort_string, sort_flags, &off)) == 2 + && off > 1) + { + int i; + char *sort_string_sep; + Z_SortKeySpec *sks = (Z_SortKeySpec *) + odr_malloc (p->odr_out, sizeof(*sks)); + Z_SortKey *sk = (Z_SortKey *) + odr_malloc (p->odr_out, sizeof(*sk)); + + arg += off; + sksl->specs[sksl->num_specs++] = sks; + sks->sortElement = (Z_SortElement *) + odr_malloc (p->odr_out, sizeof(*sks->sortElement)); + sks->sortElement->which = Z_SortElement_generic; + sks->sortElement->u.generic = sk; + + if ((sort_string_sep = strchr (sort_string, '='))) + { + Z_AttributeElement *el = (Z_AttributeElement *) + odr_malloc (p->odr_out, sizeof(*el)); + sk->which = Z_SortKey_sortAttributes; + sk->u.sortAttributes = + (Z_SortAttributes *) + odr_malloc (p->odr_out, sizeof(*sk->u.sortAttributes)); + sk->u.sortAttributes->id = oid_ent_to_oid(&bib1, oid); + sk->u.sortAttributes->list = + (Z_AttributeList *) + odr_malloc (p->odr_out, sizeof(*sk->u.sortAttributes->list)); + sk->u.sortAttributes->list->num_attributes = 1; + sk->u.sortAttributes->list->attributes = + (Z_AttributeElement **)odr_malloc (p->odr_out, + sizeof(*sk->u.sortAttributes->list->attributes)); + sk->u.sortAttributes->list->attributes[0] = el; + el->attributeSet = 0; + el->attributeType = (int *) + odr_malloc (p->odr_out, sizeof(*el->attributeType)); + *el->attributeType = atoi (sort_string); + el->which = Z_AttributeValue_numeric; + el->value.numeric = (int *) + odr_malloc (p->odr_out, sizeof(*el->value.numeric)); + *el->value.numeric = atoi (sort_string_sep + 1); + } + else + { + sk->which = Z_SortKey_sortField; + sk->u.sortField = (char *)odr_malloc (p->odr_out, strlen(sort_string)+1); + strcpy (sk->u.sortField, sort_string); + } + sks->sortRelation = (int *) + odr_malloc (p->odr_out, sizeof(*sks->sortRelation)); + *sks->sortRelation = Z_SortKeySpec_ascending; + sks->caseSensitivity = (int *) + odr_malloc (p->odr_out, sizeof(*sks->caseSensitivity)); + *sks->caseSensitivity = Z_SortKeySpec_caseSensitive; + +#ifdef ASN_COMPILED + sks->which = Z_SortKeySpec_null; + sks->u.null = odr_nullval (); +#else + sks->missingValueAction = NULL; +#endif + + for (i = 0; sort_flags[i]; i++) + { + switch (sort_flags[i]) + { + case 'a': + case 'A': + case '>': + *sks->sortRelation = Z_SortKeySpec_descending; + break; + case 'd': + case 'D': + case '<': + *sks->sortRelation = Z_SortKeySpec_ascending; + break; + case 'i': + case 'I': + *sks->caseSensitivity = Z_SortKeySpec_caseInsensitive; + break; + case 'S': + case 's': + *sks->caseSensitivity = Z_SortKeySpec_caseSensitive; + break; + } + } + } + if (!sksl->num_specs) + { + printf ("Missing sort specifications\n"); + return -1; + } + return ir_tcl_send_APDU (interp, p, apdu, "sort", *argv); +} + static IrTcl_Method ir_set_method_tab[] = { { "search", do_search, NULL}, { "searchResponse", do_searchResponse, NULL}, @@ -2898,6 +3347,7 @@ static IrTcl_Method ir_set_method_tab[] = { { "type", do_type, NULL}, { "getMarc", do_getMarc, NULL}, { "getSutrs", do_getSutrs, NULL}, + { "getXml", do_getXml, NULL}, { "getGrs", do_getGrs, NULL}, { "getExplain", do_getExplain, NULL}, { "recordType", do_recordType, NULL}, @@ -2906,6 +3356,10 @@ static IrTcl_Method ir_set_method_tab[] = { { "responseStatus", do_responseStatus, NULL}, { "loadFile", do_loadFile, NULL}, { "saveFile", do_saveFile, NULL}, + { "sort", do_sort, NULL }, + { "sortResponse", do_sortResponse, NULL}, + { "sortStatus", do_sortStatus, NULL}, + { "searchResult", do_searchResult, NULL}, { NULL, NULL} }; @@ -2916,7 +3370,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) @@ -2941,7 +3395,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"); @@ -3041,7 +3495,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; } @@ -3091,10 +3545,16 @@ 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; + char *start_term; + int code; #if CCL2RPN oident bib1; struct ccl_rpn_node *rpn; int pos; + int r; +#endif +#if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION > 0) + Tcl_DString ds; #endif if (argc <= 0) @@ -3105,16 +3565,23 @@ static int do_scan (void *o, Tcl_Interp *interp, int argc, char **argv) " scanQuery\"", NULL); return TCL_ERROR; } - logf (LOG_DEBUG, "scan %s %s", *argv, argv[2]); +#if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION > 0) + start_term = Tcl_UtfToExternalDString(0, argv[2], -1, &ds); +#else + start_term = argv[2]; +#endif + logf (LOG_DEBUG, "scan %s %s", *argv, start_term); if (!p->set_inher.num_databaseNames) { Tcl_AppendResult (interp, "no databaseNames", NULL); - return ir_tcl_error_exec (interp, argc, argv); + code = ir_tcl_error_exec (interp, argc, argv); + goto out; } if (!p->cs_link) { Tcl_AppendResult (interp, "not connected", NULL); - return ir_tcl_error_exec (interp, argc, argv); + code = ir_tcl_error_exec (interp, argc, argv); + goto out; } apdu = zget_APDU (p->odr_out, Z_APDU_scanRequest); @@ -3124,29 +3591,14 @@ static int do_scan (void *o, Tcl_Interp *interp, int argc, char **argv) req->num_databaseNames = p->set_inher.num_databaseNames; req->databaseNames = p->set_inher.databaseNames; -#if !CCL2RPN if (!(req->termListAndStartPoint = p_query_scan (p->odr_out, p->protocol_type, - &req->attributeSet, argv[2]))) + &req->attributeSet, start_term))) { Tcl_AppendResult (interp, "query syntax error", NULL); - return ir_tcl_error_exec (interp, argc, argv); + code = ir_tcl_error_exec (interp, argc, argv); + goto out; } -#else - rpn = ccl_find_str(p->bibset, argv[2], &r, &pos); - if (r) - { - Tcl_AppendResult (interp, "ccl syntax error ", ccl_err_msg(r), NULL); - return ir_tcl_error_exec (interp, argc, argv); - } - 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 req->stepSize = &obj->stepSize; req->numberOfTermsRequested = &obj->numberOfTermsRequested; req->preferredPositionInResponse = &obj->preferredPositionInResponse; @@ -3156,7 +3608,12 @@ static int do_scan (void *o, Tcl_Interp *interp, int argc, char **argv) logf (LOG_DEBUG, "preferredPositionInResponse=%d", *req->preferredPositionInResponse); - return ir_tcl_send_APDU (interp, p, apdu, "scan", *argv); + code = ir_tcl_send_APDU (interp, p, apdu, "scan", *argv); + out: +#if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION > 0) + Tcl_DStringFree (&ds); +#endif + return code; } /* @@ -3313,8 +3770,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) { @@ -3378,7 +3834,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; @@ -3427,26 +3883,63 @@ static int ir_scan_obj_mk (ClientData clientData, Tcl_Interp *interp, /* ------------------------------------------------------- */ /* - * ir_log_proc: set yaz log level + * ir_log_init_proc: set yaz log level */ static int ir_log_init_proc (ClientData clientData, Tcl_Interp *interp, int argc, char **argv) { + int lev; if (argc <= 1 || argc > 4) { Tcl_AppendResult (interp, wrongArgs, *argv, " ?level ?prefix ?filename\"", NULL); return TCL_OK; } + lev = yaz_log_mask_str (argv[1]); if (argc == 2) - log_init (log_mask_str (argv[1]), "", NULL); + yaz_log_init (lev, "", NULL); else if (argc == 3) - log_init (log_mask_str (argv[1]), argv[2], NULL); + yaz_log_init (lev, argv[2], NULL); else - log_init (log_mask_str (argv[1]), argv[2], argv[3]); + yaz_log_init (lev, argv[2], argv[3]); + if (lev & LOG_DEBUG) + odr_print_file = yaz_log_file(); + else + odr_print_file = 0; return TCL_OK; } +/* + * ir_log_proc: log yaz message + */ +static int ir_log_proc (ClientData clientData, Tcl_Interp *interp, + int argc, char **argv) +{ + int mask; + if (argc != 3) + { + Tcl_AppendResult (interp, wrongArgs, *argv, + " level string\"", NULL); + return TCL_OK; + } + mask = yaz_log_mask_str_x (argv[1], 0); + 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; +} + + /* ------------------------------------------------------- */ static void ir_initResponse (void *obj, Z_InitResponse *initrs) { @@ -3500,7 +3993,7 @@ static void ir_deleteDiags (IrTcl_Diagnostic **dst_list, int *dst_num) { int i; for (i = 0; i<*dst_num; i++) - xfree (dst_list[i]->addinfo); + xfree ((*dst_list)[i].addinfo); xfree (*dst_list); *dst_list = NULL; *dst_num = 0; @@ -3510,7 +4003,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); @@ -3521,7 +4014,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); @@ -3541,7 +4046,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; @@ -3558,8 +4064,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, 0)) + { + rl->u.dbrec.type = VAL_NONE; return; + } switch (etype->what) { case Z_External_sutrs: @@ -3593,8 +4102,11 @@ static void ir_handleDBRecord (IrTcl_Obj *p, IrTcl_RecordList *rl, if (oe->which == Z_External_octet && rl->u.dbrec.size > 0) { char *buf = (char*) oe->u.octet_aligned->buf; - if ((rl->u.dbrec.buf = ir_tcl_malloc (rl->u.dbrec.size))) + if ((rl->u.dbrec.buf = ir_tcl_malloc (rl->u.dbrec.size+1))) + { memcpy (rl->u.dbrec.buf, buf, rl->u.dbrec.size); + rl->u.dbrec.buf[rl->u.dbrec.size] = '\0'; + } } else if (rl->u.dbrec.type == VAL_SUTRS && oe->which == Z_External_sutrs) @@ -3630,10 +4142,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]; @@ -3662,12 +4180,90 @@ 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); + } +} + +static char *set_queryExpression (Z_QueryExpression *qe) +{ + char *termz = 0; + if (!qe) + return 0; + if (qe->which == Z_QueryExpression_term) + { + if (qe->u.term->queryTerm) + { + Z_Term *term = qe->u.term->queryTerm; + if (term->which == Z_Term_general) + { + termz = xmalloc (term->u.general->len+1); + memcpy (termz, term->u.general->buf, term->u.general->len); + termz[term->u.general->len] = 0; + } + } + } + return termz; +} + +static void set_searchResult (Z_OtherInformation *o, + IrTcl_SetObj *setobj) +{ + int i; + if (!o) + return ; + for (i = 0; i < o->num_elements; i++) + { + if (o->list[i]->which == Z_OtherInfo_externallyDefinedInfo) + { + ODR odr = odr_createmem (ODR_DECODE); + Z_External *ext = o->list[i]->information.externallyDefinedInfo; + Z_SearchInfoReport *sr = 0; + + if (ext->which == Z_External_single) + { + odr_setbuf (odr, ext->u.single_ASN1_type->buf, + ext->u.single_ASN1_type->len, 0); + z_SearchInfoReport (odr, &sr, 0, "searchInfo"); + } + if (ext->which == Z_External_searchResult1) + sr = ext->u.searchResult1; + if (sr) + { + int j; + reset_searchResult (setobj); + + setobj->searchResult_num = sr->num; + setobj->searchResult_terms = + xmalloc (sr->num * sizeof(*setobj->searchResult_terms)); + setobj->searchResult_count = + xmalloc (sr->num * sizeof(*setobj->searchResult_count)); + + for (j = 0; j < sr->num; j++) + { + setobj->searchResult_terms[j] = + set_queryExpression ( + sr->elements[j]->subqueryExpression); + if (sr->elements[j]->subqueryCount) + setobj->searchResult_count[j] = + *sr->elements[j]->subqueryCount; + else + setobj->searchResult_count[j] = 0; + } + } + odr_destroy (odr); + } } } @@ -3682,16 +4278,19 @@ 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_SearchResponse_none; if (searchrs->nextResultSetPosition) setobj->nextResultSetPosition = *searchrs->nextResultSetPosition; logf (LOG_DEBUG, "status %d hits %d", setobj->searchStatus, setobj->resultCount); + set_searchResult (searchrs->additionalSearchInfo, setobj); if (zrs) { const char *es; @@ -3699,10 +4298,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; + } } @@ -3721,9 +4324,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!"); } @@ -3756,67 +4363,95 @@ 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; inum_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; inum_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; +} + + +static void ir_sortResponse (void *o, Z_SortResponse *sortrs, + IrTcl_SetObj *setobj) +{ + IrTcl_Obj *p = o; + + logf (LOG_DEBUG, "Received sortResponse"); + + if (!setobj) + return; + + purge_IR_records (setobj); + + get_referenceId (&p->set_inher.referenceId, sortrs->referenceId); + + setobj->sortStatus = *sortrs->sortStatus; + + ir_deleteDiags (&setobj->nonSurrogateDiagnosticList, + &setobj->nonSurrogateDiagnosticNum); +#ifdef ASN_COMPILED + if (sortrs->diagnostics) + ir_handleDiags (&setobj->nonSurrogateDiagnosticList, + &setobj->nonSurrogateDiagnosticNum, + sortrs->diagnostics, + sortrs->num_diagnostics); +#else + if (sortrs->diagnostics) + ir_handleDiags (&setobj->nonSurrogateDiagnosticList, + &setobj->nonSurrogateDiagnosticNum, + sortrs->diagnostics->diagRecs, + sortrs->diagnostics->num_diagRecs); +#endif } /* @@ -3824,13 +4459,14 @@ 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; char *object_name; Tcl_CmdInfo cmd_info; const char *apdu_call; + int round = 0; logf(LOG_DEBUG, "Read handler fd=%d", cs_fileno(p->cs_link)); if (p->state == IR_TCL_R_Connecting) @@ -3854,7 +4490,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) @@ -3862,13 +4498,15 @@ 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 { p->state = IR_TCL_R_Reading; + round++; + yaz_log(LOG_DEBUG, "round %d", round); /* read incoming APDU */ if ((r=cs_get (p->cs_link, &p->buf_in, &p->len_in)) == 1) { @@ -3881,7 +4519,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) { @@ -3889,7 +4526,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 */ @@ -3897,7 +4534,7 @@ static void ir_select_read (ClientData clientData) p->apduOffset = -1; odr_setbuf (p->odr_in, p->buf_in, r, 0); logf (LOG_DEBUG, "cs_get ok, total size %d", r); - if (!z_APDU (p->odr_in, &apdu, 0)) + if (!z_APDU (p->odr_in, &apdu, 0, 0)) { logf (LOG_DEBUG, "cs_get failed: %s", odr_errmsg (odr_geterror (p->odr_in))); @@ -3909,15 +4546,19 @@ 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; } + if (p->odr_pr) + z_APDU(p->odr_pr, &apdu, 0, 0); /* handle APDU and invoke callback */ rq = p->request_queue; - if (!rq) - { - logf (LOG_FATAL, "Internal error. No queue entry"); - exit (1); + if (!rq) + { + /* no corresponding request. Skip it. */ + logf(LOG_DEBUG, "no corresponding request. Skipping it"); + p->state = IR_TCL_R_Idle; + return; } object_name = rq->object_name; logf (LOG_DEBUG, "Object %s", object_name); @@ -3952,6 +4593,13 @@ static void ir_select_read (ClientData clientData) apdu_call = ((IrTcl_ScanObj *) cmd_info.clientData)->scanResponse; break; + case Z_APDU_sortResponse: + p->eventType = "sort"; + ir_sortResponse (p, apdu->u.sortResponse, + (IrTcl_SetObj *) cmd_info.clientData); + apdu_call = ((IrTcl_SetObj *) + cmd_info.clientData)->sortResponse; + break; default: logf (LOG_WARN, "Received unknown APDU type (%d)", apdu->which); @@ -3978,10 +4626,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"); @@ -3992,7 +4640,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; @@ -4018,12 +4666,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; @@ -4042,7 +4690,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 */ { @@ -4101,6 +4749,11 @@ DllEntryPoint(hInst, reason, reserved) */ EXPORT (int,Irtcl_Init) (Tcl_Interp *interp) { +#if USE_TCL_STUBS + if (Tcl_InitStubs(interp, "8.1", 0) == NULL) { + return TCL_ERROR; + } +#endif Tcl_CreateCommand (interp, "ir", ir_obj_mk, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand (interp, "ir-set", ir_set_obj_mk, @@ -4109,6 +4762,11 @@ EXPORT (int,Irtcl_Init) (Tcl_Interp *interp) (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand (interp, "ir-log-init", ir_log_init_proc, (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; }