From: Adam Dickmeiss Date: Wed, 8 Mar 1995 07:28:29 +0000 (+0000) Subject: Initrequests implemented with callback support. X-Git-Tag: IRTCL.1.4~344 X-Git-Url: http://git.indexdata.com/?p=ir-tcl-moved-to-github.git;a=commitdiff_plain;h=b018d91ad37afe044cfb7a32874ea54bf4c4b7f2 Initrequests implemented with callback support. --- diff --git a/ir-tcl.c b/ir-tcl.c index a9ee487..85577da 100644 --- a/ir-tcl.c +++ b/ir-tcl.c @@ -2,12 +2,13 @@ * IR toolkit for tcl/tk * (c) Index Data 1995 * - * $Id: ir-tcl.c,v 1.1 1995-03-06 17:05:34 adam Exp $ + * $Id: ir-tcl.c,v 1.2 1995-03-08 07:28:29 adam Exp $ */ #include #include #include +#include #include #include @@ -22,78 +23,414 @@ typedef struct { COMSTACK cs_link; + + int preferredMessageSize; + int maximumMessageSize; + Odr_bitmask options; + Odr_bitmask protocolVersion; + char *idAuthentication; + char *implementationName; + char *implementationId; + + char *buf_out; + int len_out; + + char *buf_in; + int len_in; + + ODR odr_in; + ODR odr_out; + ODR odr_pr; + + Tcl_Interp *interp; + char *callback; } IRObj; -/* - * Object method +typedef struct { + IRObj *parent; +} IRSetObj; + +typedef struct { + char *name; + int (*method) (void * obj, Tcl_Interp *interp, int argc, char **argv); +} IRMethod; + +static int do_disconnect (void *obj,Tcl_Interp *interp, int argc, char **argv); + +/* + * get_parent_info: Returns information about parent object. */ -static int ir_obj_handle (ClientData clientData, Tcl_Interp *interp, - int argc, char **argv) +static int get_parent_info (Tcl_Interp *interp, const char *name, + Tcl_CmdInfo *parent_info) { - IRObj *ir = clientData; - if (argc < 2) + char parent_name[128]; + const char *csep = strrchr (name, '.'); + int pos; + + if (!csep) { - interp->result = "wrong # args"; + interp->result = "missing ."; return TCL_ERROR; } - if (!strcmp (argv[1], "comstack")) + pos = csep-name; + if (pos > 127) + pos = 127; + memcpy (parent_name, name, pos); + parent_name[pos] = '\0'; + if (!Tcl_GetCommandInfo (interp, parent_name, parent_info)) + return TCL_ERROR; + return TCL_OK; +} + +/* + * ir_method: Search for method in table and invoke method handler + */ +int ir_method (void *obj, Tcl_Interp *interp, int argc, char **argv, + IRMethod *tab) +{ + while (tab->name) { - if (argc == 3) - { - if (!strcmp (argv[2], "tcpip")) - ir->cs_link = cs_create (tcpip_type); - else if (!strcmp (argv[2], "mosi")) - ir->cs_link = cs_create (mosi_type); - else - { - interp->result = "wrong comstack type"; - return TCL_ERROR; - } - } - if (cs_type(ir->cs_link) == tcpip_type) - interp->result = "tcpip"; - else if (cs_type(ir->cs_link) == mosi_type) - interp->result = "comstack"; + if (!strcmp (tab->name, argv[1])) + return (*tab->method)(obj, interp, argc, argv); + tab++; } - else if (!strcmp (argv[1], "connect")) + Tcl_AppendResult (interp, "unknown method: ", argv[1], NULL); + return TCL_ERROR; +} + +/* + * ir_asc2bitmask: Ascii to ODR bitmask conversion + */ +int ir_asc2bitmask (const char *asc, Odr_bitmask *ob) +{ + const char *cp = asc + strlen(asc); + int bitno = 0; + + ODR_MASK_ZERO (ob); + do { - void *addr; + if (*--cp == '1') + ODR_MASK_SET (ob, bitno); + bitno++; + } while (cp != asc); + return bitno; +} - if (argc < 3) - { - interp->result = "missing hostname after connect"; +/* + * ir_strdup: Duplicate string + */ +int ir_strdup (Tcl_Interp *interp, char** p, char *s) +{ + *p = malloc (strlen(s)+1); + if (!*p) + { + interp->result = "malloc fail"; + return TCL_ERROR; + } + strcpy (*p, s); + return TCL_OK; +} + +/* ------------------------------------------------------- */ + +/* + * do_init_request: init method on IR object + */ +static int do_init_request (void *obj, Tcl_Interp *interp, + int argc, char **argv) +{ + Z_APDU apdu, *apdup; + IRObj *p = obj; + Z_InitRequest req; + char *sbuf; + int slen; + + req.referenceId = 0; + req.options = &p->options; + req.protocolVersion = &p->protocolVersion; + req.preferredMessageSize = &p->preferredMessageSize; + req.maximumRecordSize = &p->maximumMessageSize; + + req.idAuthentication = p->idAuthentication; + req.implementationId = p->implementationId; + req.implementationName = p->implementationName; + req.implementationVersion = "0.1"; + req.userInformationField = 0; + + apdu.u.initRequest = &req; + apdu.which = Z_APDU_initRequest; + apdup = &apdu; + + 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; + } + sbuf = odr_getbuf (p->odr_out, &slen); + if (cs_put (p->cs_link, sbuf, slen) < 0) + { + interp->result = "cs_put failed in init"; + return TCL_ERROR; + } + printf("Sent initializeRequest (%d bytes).\n", slen); + return TCL_OK; +} + +/* + * do_protocolVersion: Set protocol Version + */ +static int do_protocolVersion (void *obj, Tcl_Interp *interp, + int argc, char **argv) +{ + if (argc == 3) + ir_asc2bitmask (argv[2], &((IRObj *) obj)->protocolVersion); + return TCL_OK; +} + +/* + * do_options: Set options + */ +static int do_options (void *obj, Tcl_Interp *interp, + int argc, char **argv) +{ + if (argc == 3) + ir_asc2bitmask (argv[2], &((IRObj *) obj)->options); + return TCL_OK; +} + +/* + * do_preferredMessageSize: Set preferred message size + */ +static int do_preferredMessageSize (void *obj, Tcl_Interp *interp, + int argc, char **argv) +{ + if (argc == 3) + { + if (Tcl_GetInt (interp, argv[2], + &((IRObj *)obj)->preferredMessageSize)==TCL_ERROR) return TCL_ERROR; - } - if (cs_type(ir->cs_link) == tcpip_type) + } + sprintf (interp->result, "%d", ((IRObj *)obj)->preferredMessageSize); + return TCL_OK; +} + +/* + * do_maximumMessageSize: Set maximum message size + */ +static int do_maximumMessageSize (void *obj, Tcl_Interp *interp, + int argc, char **argv) +{ + if (argc == 3) + { + if (Tcl_GetInt (interp, argv[2], + &((IRObj *)obj)->maximumMessageSize)==TCL_ERROR) + return TCL_ERROR; + } + sprintf (interp->result, "%d", ((IRObj *)obj)->maximumMessageSize); + return TCL_OK; +} + + +/* + * do_implementationName: Set Implementation Name. + */ +static int do_implementationName (void *obj, Tcl_Interp *interp, + int argc, char **argv) +{ + if (argc == 3) + { + free (((IRObj*)obj)->implementationName); + if (ir_strdup (interp, &((IRObj*) obj)->implementationName, argv[2]) + == TCL_ERROR) + return TCL_ERROR; + } + Tcl_AppendResult (interp, ((IRObj*)obj)->implementationName, + (char*) NULL); + return TCL_OK; +} + +/* + * do_implementationId: Set Implementation Name. + */ +static int do_implementationId (void *obj, Tcl_Interp *interp, + int argc, char **argv) +{ + if (argc == 3) + { + free (((IRObj*)obj)->implementationId); + if (ir_strdup (interp, &((IRObj*) obj)->implementationId, argv[2]) + == TCL_ERROR) + return TCL_ERROR; + } + Tcl_AppendResult (interp, ((IRObj*)obj)->implementationId, + (char*) NULL); + return TCL_OK; +} + +/* + * do_idAuthentication: Set id Authentication + */ +static int do_idAuthentication (void *obj, Tcl_Interp *interp, + int argc, char **argv) +{ + if (argc == 3) + { + free (((IRObj*)obj)->idAuthentication); + if (ir_strdup (interp, &((IRObj*) obj)->idAuthentication, argv[2]) + == TCL_ERROR) + return TCL_ERROR; + } + Tcl_AppendResult (interp, ((IRObj*)obj)->idAuthentication, + (char*) NULL); + return TCL_OK; +} + +/* + * do_connect: connect method on IR object + */ +static int do_connect (void *obj, Tcl_Interp *interp, + int argc, char **argv) +{ + void *addr; + IRObj *p = obj; + + if (argc < 3) + { + interp->result = "missing hostname"; + return TCL_ERROR; + } + if (cs_type(p->cs_link) == tcpip_type) + { + addr = tcpip_strtoaddr (argv[2]); + if (!addr) { - addr = tcpip_strtoaddr (argv[2]); - if (!addr) - { - interp->result = "tcpip_strtoaddr fail"; - return TCL_ERROR; - } + interp->result = "tcpip_strtoaddr fail"; + return TCL_ERROR; } - else if (cs_type (ir->cs_link) == mosi_type) + printf ("tcp/ip connect %s\n", argv[2]); + } + else if (cs_type (p->cs_link) == mosi_type) + { + addr = mosi_strtoaddr (argv[2]); + if (!addr) { - addr = mosi_strtoaddr (argv[2]); - if (!addr) - { - interp->result = "mosi_strtoaddr fail"; - return TCL_ERROR; - } + interp->result = "mosi_strtoaddr fail"; + return TCL_ERROR; } - if (cs_connect (ir->cs_link, addr) < 0) + printf ("mosi connect %s\n", argv[2]); + } + if (cs_connect (p->cs_link, addr) < 0) + { + interp->result = "cs_connect fail"; + do_disconnect (p, interp, argc, argv); + return TCL_ERROR; + } + ir_select_add (cs_fileno (p->cs_link), p); + return TCL_OK; +} + +/* + * do_disconnect: disconnect method on IR object + */ +static int do_disconnect (void *obj, Tcl_Interp *interp, + int argc, char **argv) +{ + IRObj *p = obj; + + ir_select_remove (cs_fileno (p->cs_link), p); + if (cs_type (p->cs_link) == tcpip_type) + { + cs_close (p->cs_link); + p->cs_link = cs_create (tcpip_type); + } + else if (cs_type (p->cs_link) == mosi_type) + { + cs_close (p->cs_link); + p->cs_link = cs_create (mosi_type); + } + else + { + interp->result = "unknown comstack type"; + return TCL_ERROR; + } + return TCL_OK; +} + +/* + * do_comstack: comstack method on IR object + */ +static int do_comstack (void *obj, Tcl_Interp *interp, + int argc, char **argv) +{ + if (argc == 3) + { + if (!strcmp (argv[2], "tcpip")) + ((IRObj *)obj)->cs_link = cs_create (tcpip_type); + else if (!strcmp (argv[2], "mosi")) + ((IRObj *)obj)->cs_link = cs_create (mosi_type); + else { - interp->result = "cs_connect fail"; - cs_close (ir->cs_link); + interp->result = "wrong comstack type"; return TCL_ERROR; } } + if (cs_type(((IRObj *)obj)->cs_link) == tcpip_type) + interp->result = "tcpip"; + else if (cs_type(((IRObj *)obj)->cs_link) == mosi_type) + interp->result = "comstack"; return TCL_OK; } +/* + * do_callback: add callback + */ +static int do_callback (void *obj, Tcl_Interp *interp, + int argc, char **argv) +{ + IRObj *p = obj; + + if (argc == 3) + { + free (p->callback); + if (ir_strdup (interp, &p->callback, argv[2]) == TCL_ERROR) + return TCL_ERROR; + p->interp = interp; + } + return TCL_OK; +} + +/* + * ir_obj_method: IR Object methods + */ +static int ir_obj_method (ClientData clientData, Tcl_Interp *interp, + int argc, char **argv) +{ + static IRMethod tab[] = { + { "comstack", do_comstack }, + { "connect", do_connect }, + { "protocolVersion", do_protocolVersion }, + { "options", do_options }, + { "preferredMessageSize", do_preferredMessageSize }, + { "maximumMessageSize", do_maximumMessageSize }, + { "implementationName", do_implementationName }, + { "implementationId", do_implementationId }, + { "idAuthentication", do_idAuthentication }, + { "init", do_init_request }, + { "disconnect", do_disconnect }, + { "callback", do_callback }, + { NULL, NULL} + }; + if (argc < 2) + { + interp->result = "wrong # args"; + return TCL_ERROR; + } + return ir_method (clientData, interp, argc, argv, tab); +} + /* - * Object disposal + * ir_obj_delete: IR Object disposal */ static void ir_obj_delete (ClientData clientData) { @@ -101,7 +438,7 @@ static void ir_obj_delete (ClientData clientData) } /* - * Object create + * ir_obj_mk: IR Object creation */ static int ir_obj_mk (ClientData clientData, Tcl_Interp *interp, int argc, char **argv) @@ -115,20 +452,225 @@ static int ir_obj_mk (ClientData clientData, Tcl_Interp *interp, } obj = malloc (sizeof(*obj)); if (!obj) + { + interp->result = "malloc fail"; return TCL_ERROR; + } obj->cs_link = cs_create (tcpip_type); - Tcl_CreateCommand (interp, argv[1], ir_obj_handle, + obj->maximumMessageSize = 10000; + obj->preferredMessageSize = 4096; + + obj->idAuthentication = NULL; + + if (ir_strdup (interp, &obj->implementationName, "TCL/TK on YAZ") + == TCL_ERROR) + return TCL_ERROR; + + if (ir_strdup (interp, &obj->implementationId, "TCL/TK/YAZ") + == TCL_ERROR) + return TCL_ERROR; + + ODR_MASK_ZERO (&obj->protocolVersion); + ODR_MASK_SET (&obj->protocolVersion, 0); + ODR_MASK_SET (&obj->protocolVersion, 1); + + ODR_MASK_ZERO (&obj->options); + ODR_MASK_SET (&obj->options, 0); + + 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; + obj->buf_out = malloc (obj->len_out); + if (!obj->buf_out) + { + interp->result = "malloc fail"; + return TCL_ERROR; + } + odr_setbuf (obj->odr_out, obj->buf_out, obj->len_out); + + obj->len_in = 0; + obj->buf_in = NULL; + + obj->callback = NULL; + + Tcl_CreateCommand (interp, argv[1], ir_obj_method, (ClientData) obj, ir_obj_delete); return TCL_OK; } +/* ------------------------------------------------------- */ /* - * Registration + * do_query: Set query for a Set Object + */ +static int do_query (void *obj, Tcl_Interp *interp, + int argc, char **argv) +{ + return TCL_OK; +} + + +/* + * ir_set_obj_method: IR Set Object methods + */ +static int ir_set_obj_method (ClientData clientData, Tcl_Interp *interp, + int argc, char **argv) +{ + static IRMethod tab[] = { + { "query", do_query }, + { NULL, NULL} + }; + + if (argc < 2) + { + interp->result = "wrong # args"; + return TCL_ERROR; + } + return ir_method (clientData, interp, argc, argv, tab); +} + +/* + * ir_set_obj_delete: IR Set Object disposal + */ +static void ir_set_obj_delete (ClientData clientData) +{ + free ( (void*) clientData); +} + +/* + * ir_set_obj_mk: IR Set Object creation + */ +static int ir_set_obj_mk (ClientData clientData, Tcl_Interp *interp, + int argc, char **argv) +{ + Tcl_CmdInfo parent_info; + IRSetObj *obj; + + if (argc != 2) + { + interp->result = "wrong # args"; + return TCL_ERROR; + } + if (get_parent_info (interp, argv[1], &parent_info) == TCL_ERROR) + { + interp->result = "No parent"; + return TCL_ERROR; + } + obj = malloc (sizeof(*obj)); + if (!obj) + { + interp->result = "malloc fail"; + return TCL_ERROR; + } + obj->parent = (IRObj *) parent_info.clientData; + Tcl_CreateCommand (interp, argv[1], ir_set_obj_method, + (ClientData) obj, ir_set_obj_delete); + return TCL_OK; +} + +/* ------------------------------------------------------- */ + +static void ir_searchResponse (void *obj, Z_SearchResponse *searchrs) +{ + if (searchrs->searchStatus) + printf("Search was a success.\n"); + else + printf("Search was a bloomin' failure.\n"); + printf("Number of hits: %d, setno %d\n", + *searchrs->resultCount, 1); +#if 0 + if (searchrs->records) + display_records(searchrs->records); +#endif +} + +static void ir_initResponse (void *obj, Z_InitResponse *initrs) +{ + if (!*initrs->result) + printf("Connection rejected by target.\n"); + else + printf("Connection accepted by target.\n"); + if (initrs->implementationId) + printf("ID : %s\n", initrs->implementationId); + if (initrs->implementationName) + printf("Name : %s\n", initrs->implementationName); + if (initrs->implementationVersion) + printf("Version: %s\n", initrs->implementationVersion); +#if 0 + if (initrs->userInformationField) + { + printf("UserInformationfield:\n"); + odr_external(&print, (Odr_external**)&initrs-> + userInformationField, 0); + } +#endif +} + +static void ir_presentResponse (void *obj, Z_PresentResponse *presrs) +{ + printf("Received presentResponse.\n"); + if (presrs->records) + printf ("Got records\n"); + else + printf("No records\n"); +} + +void ir_select_proc (ClientData clientData) +{ + IRObj *p = clientData; + Z_APDU *apdu; + int r; + + do + { + if ((r=cs_get (p->cs_link, &p->buf_in, &p->len_in)) < 0) + { + printf ("cs_get failed\n"); + return; + } + odr_setbuf (p->odr_in, p->buf_in, r); + printf ("cs_get ok, got %d\n", r); + if (!z_APDU (p->odr_in, &apdu, 0)) + { + printf ("%s\n", odr_errlist [odr_geterror (p->odr_in)]); + return; + } + if (p->callback) + { + Tcl_Eval (p->interp, p->callback); + } + switch(apdu->which) + { + case Z_APDU_initResponse: + ir_initResponse (NULL, apdu->u.initResponse); + break; + case Z_APDU_searchResponse: + ir_searchResponse (NULL, apdu->u.searchResponse); + break; + case Z_APDU_presentResponse: + ir_presentResponse (NULL, apdu->u.presentResponse); + break; + default: + printf("Received unknown APDU type (%d).\n", + apdu->which); + } + } while (cs_more (p->cs_link)); +} + +/* ------------------------------------------------------- */ + +/* + * ir_tcl_init: Registration of TCL commands. */ int ir_tcl_init (Tcl_Interp *interp) { Tcl_CreateCommand (interp, "ir", ir_obj_mk, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); + Tcl_CreateCommand (interp, "ir-set", ir_set_obj_mk, + (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); return TCL_OK; } + + diff --git a/ir-tcl.h b/ir-tcl.h index 44708d4..62d1976 100644 --- a/ir-tcl.h +++ b/ir-tcl.h @@ -1,2 +1,6 @@ int ir_tcl_init (Tcl_Interp *interp); + +void ir_select_add (int fd, void *obj); +void ir_select_remove (int fd, void *obj); +void ir_select_proc (ClientData clientData); diff --git a/tclmain.c b/tclmain.c index 203d8aa..70d0db1 100644 --- a/tclmain.c +++ b/tclmain.c @@ -2,15 +2,24 @@ * IR toolkit for tcl/tk * (c) Index Data 1995 * - * $Id: tclmain.c,v 1.1 1995-03-06 17:05:34 adam Exp $ + * $Id: tclmain.c,v 1.2 1995-03-08 07:28:37 adam Exp $ */ +#include +#include +#include +#include + #include #include "ir-tcl.h" static char *fileName = NULL; +static fd_set fdset_tcl; + +void tcl_mainloop (Tcl_Interp *interp); + int Tcl_AppInit (Tcl_Interp *interp) { if (Tcl_Init(interp) == TCL_ERROR) @@ -40,12 +49,81 @@ int main (int argc, char **argv) } if (Tcl_AppInit(interp) != TCL_OK) { fprintf(stderr, "Tcl_AppInit failed: %s\n", interp->result); - } + } code = Tcl_EvalFile (interp, fileName); if (*interp->result != 0) printf ("%s\n", interp->result); if (code != TCL_OK) exit (1); + tcl_mainloop (interp); exit (0); } +struct callback { + void (*handle)(void *p); + void *obj; +}; + +#define MAX_CALLBACK 20 + +struct callback callback_table[MAX_CALLBACK]; + +void tcl_mainloop (Tcl_Interp *interp) +{ + int i; + int res; + int count; + char input_buf[256]; + Tcl_DString command; + + for (i=0; iresult); + printf ("[TCL]"); fflush (stdout); + } + } + } +} + +void ir_select_add (int fd, void *obj) +{ + callback_table[fd].obj = obj; + callback_table[fd].handle = ir_select_proc; +} + +void ir_select_remove (int fd, void *obj) +{ + callback_table[fd].handle = NULL; +}