+ apdu = zget_APDU (p->odr_out, Z_APDU_presentRequest);
+ req = apdu->u.presentRequest;
+
+ set_referenceId (p->odr_out, &req->referenceId,
+ obj->set_inher.referenceId);
+
+ req->resultSetId = obj->setName ? obj->setName : "Default";
+
+ req->resultSetStartPoint = &start;
+ req->numberOfRecordsRequested = &number;
+ if (obj->set_inher.preferredRecordSyntax)
+ {
+ struct oident ident;
+
+ ident.proto = p->protocol_type;
+ ident.oclass = CLASS_RECSYN;
+ ident.value = *obj->set_inher.preferredRecordSyntax;
+ logf (LOG_DEBUG, "Preferred record syntax is %d", ident.value);
+ req->preferredRecordSyntax = odr_oiddup (p->odr_out,
+ oid_getoidbyent (&ident));
+ }
+ else
+ req->preferredRecordSyntax = 0;
+
+ if (obj->set_inher.elementSetNames && *obj->set_inher.elementSetNames)
+ {
+ Z_ElementSetNames *esn = odr_malloc (p->odr_out, sizeof(*esn));
+ Z_RecordComposition *compo = odr_malloc (p->odr_out, sizeof(*compo));
+
+ esn->which = Z_ElementSetNames_generic;
+ esn->u.generic = obj->set_inher.elementSetNames;
+
+ req->recordComposition = compo;
+ compo->which = Z_RecordComp_simple;
+ compo->u.simple = esn;
+ }
+ else
+ req->recordComposition = NULL;
+ return ir_tcl_send_APDU (interp, p, apdu, "present", *argv);
+}
+
+#define IR_TCL_RECORD_ENCODING_ISO2709 1
+#define IR_TCL_RECORD_ENCODING_RAW 2
+
+typedef struct {
+ int encoding;
+ int syntax;
+ size_t size;
+} IrTcl_FileRecordHead;
+
+/*
+ * do_loadFile: Load result set from file
+ */
+static int do_loadFile (void *o, Tcl_Interp *interp,
+ int argc, char **argv)
+{
+ IrTcl_SetObj *setobj = o;
+ FILE *inf;
+ size_t size;
+ int offset;
+ int start = 1;
+ int number = 30000;
+ char *buf;
+
+ if (argc <= 0)
+ return TCL_OK;
+ if (argc < 3)
+ {
+ Tcl_AppendResult (interp, wrongArgs, *argv, " ", argv[1],
+ " filename ?start? ?number?\"", NULL);
+ return TCL_ERROR;
+ }
+ if (argc > 3)
+ start = atoi (argv[3]);
+ if (argc > 4)
+ number = atoi (argv[4]);
+ offset = start;
+
+ inf = fopen (argv[2], "r");
+ if (!inf)
+ {
+ Tcl_AppendResult (interp, "Cannot open ", argv[2], NULL);
+ return ir_tcl_error_exec (interp, argc, argv);
+ }
+ while (offset < (start+number))
+ {
+ IrTcl_FileRecordHead head;
+ IrTcl_RecordList *rl;
+
+ if (fread (&head, sizeof(head), 1, inf) < 1)
+ break;
+ rl = new_IR_record (setobj, offset,
+ Z_NamePlusRecord_databaseRecord,
+ (argc > 5) ? argv[5] : NULL);
+ rl->u.dbrec.type = head.syntax;
+ if (head.encoding == IR_TCL_RECORD_ENCODING_ISO2709)
+ {
+ if (!(buf = ir_tcl_fread_marc (inf, &size)))
+ break;
+ rl->u.dbrec.buf = buf;
+ rl->u.dbrec.size = size;
+ if (size != head.size)
+ {
+ fclose (inf);
+ Tcl_AppendResult (interp, "bad ISO2709 encoding", NULL);
+ return ir_tcl_error_exec (interp, argc, argv);
+ }
+ }
+ else if (head.encoding == IR_TCL_RECORD_ENCODING_RAW)
+ {
+ rl->u.dbrec.size = head.size;
+ rl->u.dbrec.buf = ir_tcl_malloc (head.size + 1);
+ if (fread (rl->u.dbrec.buf, rl->u.dbrec.size, 1, inf) < 1)
+ {
+ fclose (inf);
+ Tcl_AppendResult (interp, "bad raw encoding", NULL);
+ return ir_tcl_error_exec (interp, argc, argv);
+ }
+ rl->u.dbrec.buf[rl->u.dbrec.size] = '\0';
+ }
+ else
+ {
+ rl->u.dbrec.buf = NULL;
+ rl->u.dbrec.size = 0;
+ fclose (inf);
+ Tcl_AppendResult (interp, "bad encoding", NULL);
+ return ir_tcl_error_exec (interp, argc, argv);
+ }
+ offset++;
+ }
+ setobj->numberOfRecordsReturned = offset - start;
+ fclose (inf);
+ return TCL_OK;
+}
+
+/*
+ * do_saveFile: Save result set on file
+ */
+static int do_saveFile (void *o, Tcl_Interp *interp,
+ int argc, char **argv)
+{
+ IrTcl_SetObj *setobj = o;
+ FILE *outf;
+ int offset;
+ int start = 1;
+ int number = 30000;
+ IrTcl_RecordList *rl;
+
+ if (argc <= 0)
+ return TCL_OK;
+ if (argc < 3)
+ {
+ Tcl_AppendResult (interp, wrongArgs, *argv, " ", argv[1],
+ " filename ?start? ?number?\"", NULL);
+ return TCL_ERROR;
+ }
+ if (argc > 3)
+ start = atoi (argv[3]);
+ if (argc > 4)
+ number = atoi (argv[4]);
+ offset = start;
+
+ outf = fopen (argv[2], "w");
+ if (!outf)
+ {
+ Tcl_AppendResult (interp, "cannot open file", NULL);
+ return ir_tcl_error_exec (interp, argc, argv);
+ }
+ while (offset < (start+number) && (rl = find_IR_record (setobj, offset)))
+ {
+ if (rl->which == Z_NamePlusRecord_databaseRecord &&
+ rl->u.dbrec.buf && rl->u.dbrec.size)
+ {
+ IrTcl_FileRecordHead head;
+
+ head.encoding = IR_TCL_RECORD_ENCODING_RAW;
+ head.syntax = rl->u.dbrec.type;
+ head.size = rl->u.dbrec.size;
+ if (fwrite (&head, sizeof(head), 1, outf) < 1)
+ {
+ Tcl_AppendResult (interp, "cannot write", NULL);
+ return ir_tcl_error_exec (interp, argc, argv);
+ }
+ if (fwrite (rl->u.dbrec.buf, rl->u.dbrec.size, 1, outf) < 1)
+ {
+ Tcl_AppendResult (interp, "cannot write", NULL);
+ return ir_tcl_error_exec (interp, argc, argv);
+ }
+ }
+ offset++;
+ }
+ if (fclose (outf))
+ {
+ Tcl_AppendResult (interp, "cannot write ", NULL);
+ return ir_tcl_error_exec (interp, argc, argv);
+ }
+ return TCL_OK;
+}
+
+
+/* ------------------------------------------------------- */
+/*
+ * 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},
+ { "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},
+ { "getXml", do_getXml, NULL},
+ { "getGrs", do_getGrs, NULL},
+ { "getExplain", do_getExplain, NULL},
+ { "recordType", do_recordType, NULL},
+ { "recordElements", do_recordElements, NULL},
+ { "diag", do_diag, NULL},
+ { "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}
+};
+
+/*
+ * ir_set_obj_method: IR Set Object methods
+ */
+static int ir_set_obj_method (ClientData clientData, Tcl_Interp *interp,
+ int argc, char **argv)
+{
+ IrTcl_Methods tabs[3];
+ IrTcl_SetObj *p = (IrTcl_SetObj *) clientData;
+ int r;
+
+ if (argc < 2)
+ {
+ Tcl_AppendResult (interp, wrongArgs, *argv, " method args...\"", NULL);
+ return TCL_ERROR;
+ }
+ tabs[0].tab = ir_set_method_tab;
+ tabs[0].obj = p;
+ tabs[1].tab = ir_set_c_method_tab;
+ tabs[1].obj = &p->set_inher;
+ tabs[2].tab = NULL;
+
+ if (ir_tcl_method (interp, argc, argv, tabs, &r) == TCL_ERROR)
+ return ir_tcl_method_error (interp, argc, argv, tabs);
+ return r;
+}
+
+/*
+ * ir_set_obj_delete: IR Set Object disposal
+ */
+static void ir_set_obj_delete (ClientData clientData)
+{
+ IrTcl_Methods tabs[3];
+ IrTcl_SetObj *p = (IrTcl_SetObj *) clientData;
+
+ logf (LOG_DEBUG, "ir set delete");
+
+ tabs[0].tab = ir_set_method_tab;
+ tabs[0].obj = p;
+ tabs[1].tab = ir_set_c_method_tab;
+ tabs[1].obj = &p->set_inher;
+ tabs[2].tab = NULL;
+
+ ir_tcl_method (NULL, -1, NULL, tabs, NULL);
+
+ xfree (p);
+}
+
+/*
+ * ir_set_obj_init: IR Set Object initialization
+ */
+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;
+
+ if (argc < 2 || argc > 3)
+ {
+ Tcl_AppendResult (interp, wrongArgs, *argv,
+ " objSetName ?objParent?\"", NULL);
+ return TCL_ERROR;
+ }
+ obj = ir_tcl_malloc (sizeof(*obj));
+ logf (LOG_DEBUG, "ir set create %s", argv[1]);
+ if (parentData)
+ {
+ int i;
+ IrTcl_SetCObj *dst;
+ IrTcl_SetCObj *src;
+
+ 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)
+ * (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;
+ if (ir_tcl_strdup (interp, &dst->queryType, src->queryType)
+ == TCL_ERROR)
+ return TCL_ERROR;
+
+ if (ir_tcl_strdup (interp, &dst->referenceId, src->referenceId)
+ == TCL_ERROR)
+ return TCL_ERROR;
+
+ if (ir_tcl_strdup (interp, &dst->elementSetNames, src->elementSetNames)
+ == TCL_ERROR)
+ return TCL_ERROR;
+
+ if (ir_tcl_strdup (interp, &dst->smallSetElementSetNames,
+ src->smallSetElementSetNames)
+ == TCL_ERROR)
+ return TCL_ERROR;
+
+ if (ir_tcl_strdup (interp, &dst->mediumSetElementSetNames,
+ src->mediumSetElementSetNames)
+ == TCL_ERROR)
+ return TCL_ERROR;
+
+ if (src->preferredRecordSyntax &&
+ (dst->preferredRecordSyntax
+ = ir_tcl_malloc (sizeof(*dst->preferredRecordSyntax))))
+ *dst->preferredRecordSyntax = *src->preferredRecordSyntax;
+ else
+ dst->preferredRecordSyntax = NULL;
+ dst->replaceIndicator = src->replaceIndicator;
+ dst->smallSetUpperBound = src->smallSetUpperBound;
+ dst->largeSetLowerBound = src->largeSetLowerBound;
+ dst->mediumSetPresentNumber = src->mediumSetPresentNumber;
+ }
+ else
+ obj->parent = NULL;
+
+ tabs[0].tab = ir_set_method_tab;
+ tabs[0].obj = obj;
+ tabs[1].tab = NULL;
+
+ if (ir_tcl_method (interp, 0, NULL, tabs, NULL) == TCL_ERROR)
+ return TCL_ERROR;
+
+ *subData = (ClientData) 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))
+ {
+ Tcl_AppendResult (interp, "no object parent", NULL);
+ return ir_tcl_error_exec (interp, argc, argv);
+ }
+ 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,
+ 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
+};
+
+/* ------------------------------------------------------- */
+
+/*
+ * do_scan: Perform scan
+ */
+static int do_scan (void *o, Tcl_Interp *interp, int argc, char **argv)
+{
+ Z_ScanRequest *req;
+ 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)
+ return TCL_OK;
+ if (argc != 3)
+ {
+ Tcl_AppendResult (interp, wrongArgs, *argv, " ", argv[1],
+ " scanQuery\"", NULL);
+ return TCL_ERROR;
+ }
+#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);
+ code = ir_tcl_error_exec (interp, argc, argv);
+ goto out;
+ }
+ if (!p->cs_link)
+ {
+ Tcl_AppendResult (interp, "not connected", NULL);
+ code = ir_tcl_error_exec (interp, argc, argv);
+ goto out;
+ }
+
+ 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;
+
+ if (!(req->termListAndStartPoint =
+ p_query_scan (p->odr_out, p->protocol_type,
+ &req->attributeSet, start_term)))
+ {
+ Tcl_AppendResult (interp, "query syntax error", NULL);
+ code = ir_tcl_error_exec (interp, argc, argv);
+ goto out;
+ }
+ req->stepSize = &obj->stepSize;
+ req->numberOfTermsRequested = &obj->numberOfTermsRequested;
+ req->preferredPositionInResponse = &obj->preferredPositionInResponse;
+ logf (LOG_DEBUG, "stepSize=%d", *req->stepSize);
+ logf (LOG_DEBUG, "numberOfTermsRequested=%d",
+ *req->numberOfTermsRequested);
+ logf (LOG_DEBUG, "preferredPositionInResponse=%d",
+ *req->preferredPositionInResponse);
+
+ 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;
+}
+
+/*
+ * do_scanResponse: add scan response handler
+ */
+static int do_scanResponse (void *o, Tcl_Interp *interp,
+ int argc, char **argv)
+{
+ IrTcl_ScanObj *obj = o;
+
+ if (argc == 0)
+ {
+ obj->scanResponse = NULL;
+ return TCL_OK;
+ }
+ else if (argc == -1)
+ return ir_tcl_strdel (interp, &obj->scanResponse);
+ if (argc == 3)
+ {
+ xfree (obj->scanResponse);
+ if (argv[2][0])
+ {
+ if (ir_tcl_strdup (interp, &obj->scanResponse, argv[2])
+ == TCL_ERROR)
+ return TCL_ERROR;
+ }
+ else
+ obj->scanResponse = NULL;
+ }
+ return TCL_OK;
+}
+
+/*
+ * do_stepSize: Set/get replace Step Size
+ */
+static int do_stepSize (void *obj, Tcl_Interp *interp,
+ int argc, char **argv)
+{
+ IrTcl_ScanObj *p = obj;
+ if (argc <= 0)
+ {
+ p->stepSize = 0;
+ return TCL_OK;
+ }
+ return ir_tcl_get_set_int (&p->stepSize, interp, argc, argv);
+}
+
+/*
+ * do_numberOfTermsRequested: Set/get Number of Terms requested
+ */
+static int do_numberOfTermsRequested (void *obj, Tcl_Interp *interp,
+ int argc, char **argv)
+{
+ IrTcl_ScanObj *p = obj;
+
+ if (argc <= 0)
+ {
+ p->numberOfTermsRequested = 20;
+ return TCL_OK;
+ }
+ return ir_tcl_get_set_int (&p->numberOfTermsRequested, interp, argc, argv);
+}
+
+
+/*
+ * do_preferredPositionInResponse: Set/get preferred Position
+ */
+static int do_preferredPositionInResponse (void *obj, Tcl_Interp *interp,
+ int argc, char **argv)
+{
+ IrTcl_ScanObj *p = obj;
+
+ if (argc <= 0)
+ {
+ p->preferredPositionInResponse = 1;
+ return TCL_OK;
+ }
+ return ir_tcl_get_set_int (&p->preferredPositionInResponse, interp,
+ argc, argv);
+}
+
+/*
+ * do_scanStatus: Get scan status
+ */
+static int do_scanStatus (void *obj, Tcl_Interp *interp,
+ int argc, char **argv)
+{
+ IrTcl_ScanObj *p = obj;
+
+ if (argc <= 0)
+ return TCL_OK;
+ return ir_tcl_get_set_int (&p->scanStatus, interp, argc, argv);
+}
+
+/*
+ * do_numberOfEntriesReturned: Get number of Entries returned
+ */
+static int do_numberOfEntriesReturned (void *obj, Tcl_Interp *interp,
+ int argc, char **argv)
+{
+ IrTcl_ScanObj *p = obj;
+
+ if (argc <= 0)
+ return TCL_OK;
+ return ir_tcl_get_set_int (&p->numberOfEntriesReturned, interp,
+ argc, argv);
+}
+
+/*
+ * do_positionOfTerm: Get position of Term
+ */
+static int do_positionOfTerm (void *obj, Tcl_Interp *interp,
+ int argc, char **argv)
+{
+ IrTcl_ScanObj *p = obj;
+
+ if (argc <= 0)
+ return TCL_OK;
+ return ir_tcl_get_set_int (&p->positionOfTerm, interp, argc, argv);
+}
+
+/*
+ * do_scanLine: get Scan Line (surrogate or normal) after response
+ */
+static int do_scanLine (void *obj, Tcl_Interp *interp, int argc, char **argv)
+{
+ IrTcl_ScanObj *p = obj;
+ int i;
+ char numstr[20];
+
+ if (argc == 0)
+ {
+ p->entries_flag = 0;
+ p->entries = NULL;
+ p->nonSurrogateDiagnosticNum = 0;
+ p->nonSurrogateDiagnosticList = 0;
+ return TCL_OK;
+ }
+ else if (argc == -1)
+ {
+ p->entries_flag = 0;
+ /* release entries */
+ p->entries = NULL;
+
+ ir_deleteDiags (&p->nonSurrogateDiagnosticList,
+ &p->nonSurrogateDiagnosticNum);
+ return TCL_OK;
+ }
+ if (argc != 3)
+ {
+ Tcl_AppendResult (interp, wrongArgs, *argv, " ", argv[1],
+ " position\"", NULL);
+ return TCL_ERROR;
+ }
+ if (Tcl_GetInt (interp, argv[2], &i) == TCL_ERROR)
+ return TCL_ERROR;
+ if (!p->entries_flag || !p->entries || i >= p->num_entries || i < 0)
+ return TCL_OK;
+ switch (p->entries[i].which)
+ {
+ case Z_Entry_termInfo:
+ Tcl_AppendElement (interp, "T");
+ if (p->entries[i].u.term.buf)
+ Tcl_AppendElement (interp, p->entries[i].u.term.buf);
+ else
+ Tcl_AppendElement (interp, "");
+ sprintf (numstr, "%d", p->entries[i].u.term.globalOccurrences);
+ Tcl_AppendElement (interp, numstr);
+ break;
+ case Z_Entry_surrogateDiagnostic:
+ Tcl_AppendElement (interp, "SD");
+ return ir_diagResult (interp, p->entries[i].u.diag.list,
+ p->entries[i].u.diag.num);
+ break;
+ }
+ return TCL_OK;
+}
+
+static IrTcl_Method ir_scan_method_tab[] = {
+ { "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}
+};
+
+/*
+ * ir_scan_obj_method: IR Scan Object methods
+ */
+static int ir_scan_obj_method (ClientData clientData, Tcl_Interp *interp,
+ int argc, char **argv)
+{
+ IrTcl_Methods tabs[2];
+ int r;
+
+ if (argc < 2)
+ {
+ Tcl_AppendResult (interp, wrongArgs, *argv, " method args...\"", NULL);
+ return TCL_ERROR;
+ }
+ tabs[0].tab = ir_scan_method_tab;
+ tabs[0].obj = clientData;
+ tabs[1].tab = NULL;
+
+ if (ir_tcl_method (interp, argc, argv, tabs, &r) == TCL_ERROR)
+ return ir_tcl_method_error (interp, argc, argv, tabs);
+ return r;
+}
+
+/*
+ * ir_scan_obj_delete: IR Scan Object disposal
+ */
+static void ir_scan_obj_delete (ClientData clientData)
+{
+ IrTcl_Methods tabs[2];
+ IrTcl_ScanObj *obj = (IrTcl_ScanObj *) clientData;
+
+ tabs[0].tab = ir_scan_method_tab;
+ tabs[0].obj = obj;
+ tabs[1].tab = NULL;
+
+ ir_tcl_method (NULL, -1, NULL, tabs, NULL);
+ xfree (obj);
+}
+
+/*
+ * ir_scan_obj_mk: IR Scan Object creation
+ */
+static int ir_scan_obj_mk (ClientData clientData, Tcl_Interp *interp,
+ int argc, char **argv)
+{
+ Tcl_CmdInfo parent_info;
+ IrTcl_ScanObj *obj;
+ IrTcl_Methods tabs[2];
+
+ if (argc != 3)
+ {
+ Tcl_AppendResult (interp, wrongArgs, *argv,
+ "objScanName objParentName\"", NULL);
+ return TCL_ERROR;
+ }
+ logf (LOG_DEBUG, "ir scan create %s", argv[1]);
+ if (!Tcl_GetCommandInfo (interp, argv[2], &parent_info))
+ {
+ Tcl_AppendResult (interp, "no object parent", NULL);
+ return ir_tcl_error_exec (interp, argc, argv);
+ }
+ obj = ir_tcl_malloc (sizeof(*obj));
+ obj->parent = (IrTcl_Obj *) parent_info.clientData;
+
+ tabs[0].tab = ir_scan_method_tab;
+ tabs[0].obj = obj;
+ tabs[1].tab = NULL;
+
+ 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);
+ return TCL_OK;
+}
+
+/* ------------------------------------------------------- */
+
+/*
+ * 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)
+ yaz_log_init (lev, "", NULL);
+ else if (argc == 3)
+ yaz_log_init (lev, argv[2], NULL);
+ else
+ 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)
+{
+ IrTcl_Obj *p = obj;
+
+ p->initResult = *initrs->result ? 1 : 0;
+ if (!*initrs->result)
+ logf (LOG_DEBUG, "Connection rejected by target");
+ else
+ logf (LOG_DEBUG, "Connection accepted by target");
+
+ get_referenceId (&p->set_inher.referenceId, initrs->referenceId);
+
+ xfree (p->targetImplementationId);
+ ir_tcl_strdup (p->interp, &p->targetImplementationId,
+ initrs->implementationId);
+ xfree (p->targetImplementationName);
+ ir_tcl_strdup (p->interp, &p->targetImplementationName,
+ initrs->implementationName);
+ xfree (p->targetImplementationVersion);
+ ir_tcl_strdup (p->interp, &p->targetImplementationVersion,
+ initrs->implementationVersion);
+
+ p->maximumRecordSize = *initrs->maximumRecordSize;
+ p->preferredMessageSize = *initrs->preferredMessageSize;
+
+ memcpy (&p->options, initrs->options, sizeof(initrs->options));
+ memcpy (&p->protocolVersion, initrs->protocolVersion,
+ sizeof(initrs->protocolVersion));
+ xfree (p->userInformationField);
+ p->userInformationField = NULL;
+ if (initrs->userInformationField)
+ {
+ int len;
+
+ if (initrs->userInformationField->which == ODR_EXTERNAL_octet &&
+ (p->userInformationField =
+ ir_tcl_malloc ((len =
+ initrs->userInformationField->
+ u.octet_aligned->len) +1)))
+ {
+ memcpy (p->userInformationField,
+ initrs->userInformationField->u.octet_aligned->buf,
+ len);
+ (p->userInformationField)[len] = '\0';
+ }
+ }
+}
+
+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);
+ *dst_list = NULL;
+ *dst_num = 0;
+}
+
+static void ir_handleDiags (IrTcl_Diagnostic **dst_list, int *dst_num,
+ Z_DiagRec **list, int num)
+{
+ int i;
+ char *addinfo = NULL;
+
+ *dst_num = num;
+ *dst_list = ir_tcl_malloc (sizeof(**dst_list) * num);
+ for (i = 0; i<num; i++)