+ IrTcl_Methods tab[3];
+ IrTcl_Obj *p = clientData;
+
+ if (argc < 2)
+ return ir_method_r (clientData, interp, argc, argv, ir_method_tab);
+
+ tab[0].tab = ir_method_tab;
+ tab[0].obj = p;
+ tab[1].tab = ir_set_c_method_tab;
+ tab[1].obj = &p->set_inher;
+ tab[2].tab = NULL;
+
+ return ir_method (interp, argc, argv, tab);
+}
+
+/*
+ * ir_obj_delete: IR Object disposal
+ */
+static void ir_obj_delete (ClientData clientData)
+{
+ IrTcl_Obj *obj = clientData;
+ IrTcl_Methods tab[3];
+
+ --(obj->ref_count);
+ if (obj->ref_count > 0)
+ return;
+ assert (obj->ref_count == 0);
+
+ tab[0].tab = ir_method_tab;
+ tab[0].obj = obj;
+ tab[1].tab = ir_set_c_method_tab;
+ tab[1].obj = &obj->set_inher;
+ tab[2].tab = NULL;
+
+ ir_method (NULL, -1, NULL, tab);
+ odr_destroy (obj->odr_in);
+ odr_destroy (obj->odr_out);
+ odr_destroy (obj->odr_pr);
+ free (obj->buf_out);
+ free (obj->buf_in);
+ free (obj);
+}
+
+/*
+ * ir_obj_mk: IR Object creation
+ */
+static int ir_obj_mk (ClientData clientData, Tcl_Interp *interp,
+ int argc, char **argv)
+{
+ IrTcl_Methods tab[3];
+ IrTcl_Obj *obj;
+#if CCL2RPN
+ FILE *inf;
+#endif
+
+ if (argc != 2)
+ {
+ interp->result = "wrong # args";
+ return TCL_ERROR;
+ }
+ if (!(obj = ir_malloc (interp, sizeof(*obj))))
+ return TCL_ERROR;
+
+ obj->ref_count = 1;
+#if CCL2RPN
+ obj->bibset = ccl_qual_mk ();
+ if ((inf = fopen ("default.bib", "r")))
+ {
+ ccl_qual_file (obj->bibset, inf);
+ fclose (inf);
+ }
+#endif
+
+ obj->odr_in = odr_createmem (ODR_DECODE);
+ obj->odr_out = odr_createmem (ODR_ENCODE);
+ obj->odr_pr = odr_createmem (ODR_PRINT);
+
+ obj->len_out = 10000;
+ if (!(obj->buf_out = ir_malloc (interp, obj->len_out)))
+ return TCL_ERROR;
+ odr_setbuf (obj->odr_out, obj->buf_out, obj->len_out, 0);
+
+ obj->len_in = 0;
+ obj->buf_in = NULL;
+
+ tab[0].tab = ir_method_tab;
+ tab[0].obj = obj;
+ tab[1].tab = ir_set_c_method_tab;
+ tab[1].obj = &obj->set_inher;
+ tab[2].tab = NULL;
+
+ if (ir_method (interp, 0, NULL, tab) == TCL_ERROR)
+ return TCL_ERROR;
+ Tcl_CreateCommand (interp, argv[1], ir_obj_method,
+ (ClientData) obj, ir_obj_delete);
+ return TCL_OK;
+}
+
+/* ------------------------------------------------------- */
+/*
+ * do_search: Do search request
+ */
+static int do_search (void *o, Tcl_Interp *interp,
+ int argc, char **argv)
+{
+ Z_SearchRequest req;
+ Z_Query query;
+ Z_APDU apdu, *apdup = &apdu;
+ Odr_oct ccl_query;
+ IrTcl_SetObj *obj = o;
+ IrTcl_Obj *p = obj->parent;
+ int r;
+ oident bib1;
+
+ if (argc <= 0)
+ return TCL_OK;
+
+ p->set_child = o;
+ if (argc != 3)
+ {
+ interp->result = "wrong # args";
+ return TCL_ERROR;
+ }
+ if (!obj->set_inher.num_databaseNames)
+ {
+ interp->result = "no databaseNames";
+ return TCL_ERROR;
+ }
+ if (!p->cs_link)
+ {
+ interp->result = "not connected";
+ return TCL_ERROR;
+ }
+ odr_reset (p->odr_out);
+ apdu.which = Z_APDU_searchRequest;
+ apdu.u.searchRequest = &req;
+
+ bib1.proto = PROTO_Z3950;
+ bib1.class = CLASS_ATTSET;
+ bib1.value = VAL_BIB1;
+
+ set_referenceId (p->odr_out, &req.referenceId, obj->set_inher.referenceId);
+
+ req.smallSetUpperBound = &obj->set_inher.smallSetUpperBound;
+ req.largeSetLowerBound = &obj->set_inher.largeSetLowerBound;
+ req.mediumSetPresentNumber = &obj->set_inher.mediumSetPresentNumber;
+ req.replaceIndicator = &obj->set_inher.replaceIndicator;
+ req.resultSetName = obj->setName ? obj->setName : "Default";
+ logf (LOG_DEBUG, "Search, resultSetName %s", req.resultSetName);
+ req.num_databaseNames = obj->set_inher.num_databaseNames;
+ req.databaseNames = obj->set_inher.databaseNames;
+ for (r=0; r < obj->set_inher.num_databaseNames; r++)
+ logf (LOG_DEBUG, " Database %s", obj->set_inher.databaseNames[r]);
+ req.smallSetElementSetNames = 0;
+ req.mediumSetElementSetNames = 0;
+ req.preferredRecordSyntax = 0;
+ req.query = &query;
+
+ if (!strcmp (obj->set_inher.queryType, "rpn"))
+ {
+ Z_RPNQuery *RPNquery;
+
+ RPNquery = p_query_rpn (p->odr_out, argv[2]);
+ if (!RPNquery)
+ {
+ Tcl_AppendResult (interp, "Syntax error in query", NULL);
+ return TCL_ERROR;
+ }
+ RPNquery->attributeSetId = oid_getoidbyent (&bib1);
+ query.which = Z_Query_type_1;
+ query.u.type_1 = RPNquery;
+ logf (LOG_DEBUG, "RPN");
+ }
+#if CCL2RPN
+ else if (!strcmp (obj->set_inher.queryType, "cclrpn"))
+ {
+ int error;
+ int pos;
+ struct ccl_rpn_node *rpn;
+ Z_RPNQuery *RPNquery;
+
+ rpn = ccl_find_str(p->bibset, argv[2], &error, &pos);
+ if (error)
+ {
+ Tcl_AppendResult (interp, "CCL error: ",
+ ccl_err_msg(error), NULL);
+ return TCL_ERROR;
+ }
+ ccl_pr_tree (rpn, stderr);
+ fprintf (stderr, "\n");
+ assert((RPNquery = ccl_rpn_query(rpn)));
+ RPNquery->attributeSetId = oid_getoidbyent (&bib1);
+ query.which = Z_Query_type_1;
+ query.u.type_1 = RPNquery;
+ logf (LOG_DEBUG, "CCLRPN");
+ }
+#endif
+ else if (!strcmp (obj->set_inher.queryType, "ccl"))
+ {
+ 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]);
+ logf (LOG_DEBUG, "CCL");
+ }
+ else
+ {
+ interp->result = "unknown query method";
+ return TCL_ERROR;
+ }
+ if (!z_APDU (p->odr_out, &apdup, 0))
+ {
+ interp->result = odr_errlist [odr_geterror (p->odr_out)];
+ odr_reset (p->odr_out);
+ return TCL_ERROR;
+ }
+ p->sbuf = odr_getbuf (p->odr_out, &p->slen, NULL);
+ if ((r=cs_put (p->cs_link, p->sbuf, p->slen)) < 0)
+ {
+ interp->result = "cs_put failed in search";
+ return TCL_ERROR;
+ }
+ else if (r == 1)
+ {
+ ir_select_add_write (cs_fileno(p->cs_link), p);
+ logf (LOG_DEBUG, "Sent part of searchRequest (%d bytes)", p->slen);
+ }
+ else
+ {
+ logf (LOG_DEBUG, "Whole search request (%d bytes)", p->slen);
+ }
+ return TCL_OK;
+}
+
+/*
+ * do_resultCount: Get number of hits
+ */
+static int do_resultCount (void *o, Tcl_Interp *interp,
+ int argc, char **argv)
+{
+ IrTcl_SetObj *obj = o;
+
+ if (argc <= 0)
+ return TCL_OK;
+ return get_set_int (&obj->resultCount, interp, argc, argv);
+}
+
+/*
+ * do_searchStatus: Get search status (after search response)
+ */
+static int do_searchStatus (void *o, Tcl_Interp *interp,
+ int argc, char **argv)
+{
+ IrTcl_SetObj *obj = o;
+
+ if (argc <= 0)
+ return TCL_OK;
+ return get_set_int (&obj->searchStatus, interp, argc, argv);
+}
+
+/*
+ * do_presentStatus: Get search status (after search/present response)
+ */
+static int do_presentStatus (void *o, Tcl_Interp *interp,
+ int argc, char **argv)
+{
+ IrTcl_SetObj *obj = o;
+
+ if (argc <= 0)
+ return TCL_OK;
+ return get_set_int (&obj->presentStatus, interp, argc, argv);
+}
+
+/*
+ * do_nextResultSetPosition: Get next result set position
+ * (after search/present response)
+ */
+static int do_nextResultSetPosition (void *o, Tcl_Interp *interp,
+ int argc, char **argv)
+{
+ IrTcl_SetObj *obj = o;
+
+ if (argc <= 0)
+ return TCL_OK;
+ return get_set_int (&obj->nextResultSetPosition, interp, argc, argv);
+}
+
+/*
+ * do_setName: Set result Set name
+ */
+static int do_setName (void *o, Tcl_Interp *interp,
+ int argc, char **argv)
+{
+ IrTcl_SetObj *obj = o;
+
+ if (argc == 0)
+ return ir_strdup (interp, &obj->setName, "Default");
+ else if (argc == -1)
+ return ir_strdel (interp, &obj->setName);
+ if (argc == 3)
+ {
+ free (obj->setName);
+ if (ir_strdup (interp, &obj->setName, argv[2])
+ == TCL_ERROR)
+ return TCL_ERROR;
+ }
+ Tcl_AppendElement (interp, obj->setName);
+ return TCL_OK;
+}
+
+/*
+ * do_numberOfRecordsReturned: Get number of records returned
+ */
+static int do_numberOfRecordsReturned (void *o, Tcl_Interp *interp,
+ int argc, char **argv)
+{
+ IrTcl_SetObj *obj = o;
+
+ if (argc < 0)
+ return TCL_OK;
+ return get_set_int (&obj->numberOfRecordsReturned, interp, argc, argv);
+}
+
+/*
+ * do_type: Return type (if any) at position.
+ */
+static int do_type (void *o, Tcl_Interp *interp, int argc, char **argv)
+{
+ IrTcl_SetObj *obj = o;
+ int offset;
+ IrTcl_RecordList *rl;
+
+ if (argc == 0)
+ {
+ obj->record_list = NULL;
+ return TCL_OK;
+ }
+ else if (argc == -1)
+ {
+ delete_IR_records (obj);
+ return TCL_OK;
+ }
+ if (argc < 3)
+ {
+ sprintf (interp->result, "wrong # args");
+ return TCL_ERROR;
+ }
+ if (Tcl_GetInt (interp, argv[2], &offset)==TCL_ERROR)
+ return TCL_ERROR;
+ rl = find_IR_record (obj, offset);
+ if (!rl)
+ return TCL_OK;
+ switch (rl->which)
+ {
+ case Z_NamePlusRecord_databaseRecord:
+ interp->result = "DB";
+ break;
+ case Z_NamePlusRecord_surrogateDiagnostic:
+ interp->result = "SD";
+ break;
+ }
+ return TCL_OK;
+}
+
+/*
+ * do_diag: Return diagnostic record info
+ */
+static int do_diag (void *o, Tcl_Interp *interp, int argc, char **argv)
+{
+ IrTcl_SetObj *obj = o;
+ int offset;
+ IrTcl_RecordList *rl;
+ char buf[20];
+ const char *cp;
+
+ if (argc <= 0)
+ return TCL_OK;
+ if (argc < 3)
+ {
+ sprintf (interp->result, "wrong # args");
+ 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_surrogateDiagnostic)
+ {
+ Tcl_AppendResult (interp, "No Diagnostic record at #", argv[2], NULL);
+ return TCL_ERROR;
+ }
+
+ sprintf (buf, "%d", rl->u.diag.condition);
+ Tcl_AppendElement (interp, buf);
+ cp = diagbib1_str (rl->u.diag.condition);
+ if (cp)
+ Tcl_AppendElement (interp, (char*) cp);
+ else
+ Tcl_AppendElement (interp, "");
+ if (rl->u.diag.addinfo)
+ Tcl_AppendElement (interp, (char*) rl->u.diag.addinfo);
+ else
+ Tcl_AppendElement (interp, "");
+ return TCL_OK;
+}
+
+/*
+ * do_getMarc: Get ISO2709 Record lines/fields
+ */
+static int do_getMarc (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 < 7)
+ {
+ sprintf (interp->result, "wrong # args");
+ 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 MARC record at #", argv[2], NULL);
+ return TCL_ERROR;
+ }
+ return ir_tcl_get_marc (interp, rl->u.dbrec.buf, argc, argv);
+}
+
+
+/*
+ * do_responseStatus: Return response status (present or search)
+ */
+static int do_responseStatus (void *o, Tcl_Interp *interp,
+ int argc, char **argv)
+{
+ IrTcl_SetObj *obj = o;
+
+ if (argc == 0)
+ {
+ obj->recordFlag = 0;
+ obj->addinfo = NULL;
+ return TCL_OK;
+ }
+ else if (argc == -1)
+ return ir_strdel (interp, &obj->addinfo);
+ if (!obj->recordFlag)
+ {
+ Tcl_AppendElement (interp, "OK");
+ return TCL_OK;
+ }
+ switch (obj->which)
+ {
+ case Z_Records_DBOSD:
+ Tcl_AppendElement (interp, "DBOSD");
+ break;
+ case Z_Records_NSD:
+ return mk_nonSurrogateDiagnostics (interp, obj->condition,
+ obj->addinfo);
+ }
+ return TCL_OK;
+}
+
+/*
+ * do_present: Perform Present Request
+ */
+
+static int do_present (void *o, Tcl_Interp *interp,
+ int argc, char **argv)
+{
+ IrTcl_SetObj *obj = o;
+ IrTcl_Obj *p = obj->parent;
+ Z_APDU apdu, *apdup = &apdu;
+ Z_PresentRequest req;
+ int start;
+ int number;
+ int r;
+
+ if (argc <= 0)
+ return TCL_OK;
+ if (argc >= 3)
+ {
+ if (Tcl_GetInt (interp, argv[2], &start) == TCL_ERROR)
+ return TCL_ERROR;
+ }
+ else
+ start = 1;
+ if (argc >= 4)
+ {
+ if (Tcl_GetInt (interp, argv[3], &number) == TCL_ERROR)
+ return TCL_ERROR;
+ }
+ else
+ number = 10;
+ if (!p->cs_link)
+ {
+ interp->result = "not connected";
+ return TCL_ERROR;
+ }
+ odr_reset (p->odr_out);
+ obj->start = start;
+ obj->number = number;
+
+ apdu.which = Z_APDU_presentRequest;
+ apdu.u.presentRequest = &req;
+
+ set_referenceId (p->odr_out, &req.referenceId, obj->set_inher.referenceId);
+
+ req.resultSetId = obj->setName ? obj->setName : "Default";
+
+ req.resultSetStartPoint = &start;
+ req.numberOfRecordsRequested = &number;
+ req.elementSetNames = 0;
+ req.preferredRecordSyntax = 0;
+
+ if (!z_APDU (p->odr_out, &apdup, 0))
+ {
+ interp->result = odr_errlist [odr_geterror (p->odr_out)];
+ odr_reset (p->odr_out);
+ return TCL_ERROR;
+ }
+ p->sbuf = odr_getbuf (p->odr_out, &p->slen, NULL);
+ if ((r=cs_put (p->cs_link, p->sbuf, p->slen)) < 0)
+ {
+ interp->result = "cs_put failed in present";
+ return TCL_ERROR;
+ }
+ else if (r == 1)
+ {
+ ir_select_add_write (cs_fileno(p->cs_link), p);
+ logf (LOG_DEBUG, "Part of present request, start=%d, num=%d"
+ " (%d bytes)", start, number, p->slen);
+ }
+ else
+ {
+ logf (LOG_DEBUG, "Whole present request, start=%d, num=%d"
+ " (%d bytes)", start, number, p->slen);
+ }
+ return TCL_OK;
+}
+
+/*
+ * 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 no = 1;
+ char *buf;
+
+ if (argc <= 0)
+ return TCL_OK;
+ if (argc < 3)
+ {
+ interp->result = "wrong # args";
+ return TCL_ERROR;
+ }
+ inf = fopen (argv[2], "r");
+ if (!inf)
+ {
+ Tcl_AppendResult (interp, "Cannot open ", argv[2], NULL);
+ return TCL_ERROR;
+ }
+ while ((buf = ir_tcl_fread_marc (inf, &size)))
+ {
+ IrTcl_RecordList *rl;
+
+ rl = new_IR_record (setobj, no, Z_NamePlusRecord_databaseRecord);
+ rl->u.dbrec.buf = buf;
+ rl->u.dbrec.size = size;
+ no++;
+ }
+ setobj->numberOfRecordsReturned = no-1;
+ fclose (inf);
+ return TCL_OK;
+}
+
+static IrTcl_Method ir_set_method_tab[] = {
+ { 0, "search", do_search },
+ { 0, "searchStatus", do_searchStatus },
+ { 0, "presentStatus", do_presentStatus },
+ { 0, "nextResultSetPosition", do_nextResultSetPosition },
+ { 0, "setName", do_setName },
+ { 0, "resultCount", do_resultCount },
+ { 0, "numberOfRecordsReturned", do_numberOfRecordsReturned },
+ { 0, "present", do_present },
+ { 0, "type", do_type },
+ { 0, "getMarc", do_getMarc },
+ { 0, "diag", do_diag },
+ { 0, "responseStatus", do_responseStatus },
+ { 0, "loadFile", do_loadFile },
+ { 0, 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 = clientData;
+