diff options
author | William Joye <wjoye@cfa.harvard.edu> | 2017-10-26 16:45:12 (GMT) |
---|---|---|
committer | William Joye <wjoye@cfa.harvard.edu> | 2017-10-26 16:45:12 (GMT) |
commit | 6054f36bb658916bd231b9002efb94444e2871c8 (patch) | |
tree | a815500ec9bf0e100f4075a825213605c382def0 /tcl.c | |
download | blt-6054f36bb658916bd231b9002efb94444e2871c8.zip blt-6054f36bb658916bd231b9002efb94444e2871c8.tar.gz blt-6054f36bb658916bd231b9002efb94444e2871c8.tar.bz2 |
Squashed 'xpa/' content from commit d6a54301
git-subtree-dir: xpa
git-subtree-split: d6a543018b46c5a6c47b5ff91e0e131549595ca6
Diffstat (limited to 'tcl.c')
-rw-r--r-- | tcl.c | 2773 |
1 files changed, 2773 insertions, 0 deletions
@@ -0,0 +1,2773 @@ +/* + * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory + */ + +#include <xpap.h> + +#if HAVE_TCL + +#include <tcl.h> + +/* + *---------------------------------------------------------------------------- + * + * + * Private Routines and Data + * + * + *---------------------------------------------------------------------------- + */ + +/* with Tcl 8.4, some function prototypes have added CONST qualifiers, + which we try to deal with in a backward-compatible way */ +#define XCONST84 +#if TCL_MAJOR_VERSION >= 8 +#if TCL_MINOR_VERSION >= 4 +#undef XCONST84 +#define XCONST84 CONST +#endif +#endif + +#ifdef NULLSTRING +#undef NULLSTRING +#endif +#define NULLSTRING "" + +#define TCL_NULLSTR(s) (!s || !*s || !strcmp(s, "{}")) + +#define TY_CLIENT 1 +#define TY_SERVER 2 + +#ifndef MAX_XPAS +#define MAX_XPAS 10000 +#endif + +/* + * + * record struct for client_data for XPATcl[Send,Receive,Info] routines + * + */ +typedef struct xpatclclientdatarec{ + Tcl_Interp *interp; + char *callback; + char *client_data; +} *XPATclClientData, XPATclClientDataRec; + + +/* + *---------------------------------------------------------------------------- + * + * Routine: Tcl_GetXPAFromObj + * + * Purpose: convert string to XPA handle + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +Tcl_GetXPAFromObj(Tcl_Interp *interp, Tcl_Obj *obj, int flag, XPA *xpa) +#else +static int Tcl_GetXPAFromObj(interp, obj, flag, xpa) + Tcl_Interp *interp; + Tcl_Obj *obj; + int flag; + XPA *xpa; +#endif +{ + char *s; + void *lval; + Tcl_Obj *resultPtr; + + /* get result pointer */ + resultPtr = Tcl_GetObjResult(interp); + + if( (s = Tcl_GetStringFromObj(obj, NULL)) == NULL ){ + return(TCL_ERROR); + } + if( strncmp(s, "xpa_", 4) || (sscanf(&(s[4]), "%p", &lval) != 1) ){ + Tcl_SetStringObj(resultPtr, "XPA$ERROR: invalid xpa handle", -1); + return(TCL_ERROR); + } + *xpa = (XPA)lval; + /* make sure its a valid xpa */ + switch(flag){ + case TY_CLIENT: + if( !XPAClientValid(*xpa) ){ + Tcl_SetStringObj(resultPtr, "XPA$ERROR: invalid xpa client handle", -1); + return(TCL_ERROR); + } + break; + case TY_SERVER: + if( !XPAValid(*xpa) ){ + Tcl_SetStringObj(resultPtr, "XPA$ERROR: invalid xpa server handle", -1); + return(TCL_ERROR); + } + break; + } + return(TCL_OK); +} + + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPATclHandler + * + * Purpose: common handler for access points written in tcl + * execute the tcl receive command with xpa arguments + * used instead of Tcl_Eval so we can avoid interpreting either + * paramlist or buf + * + * + * Returns: 0 on success, -1 on failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPATclHandler (void *client_data, void *call_data, char *paramlist, + char *buf, int len, int nargs) +#else +static int XPATclHandler(client_data, call_data, paramlist, buf, len, nargs) + void *client_data; + void *call_data; + char *paramlist; + char *buf; + int len; + int nargs; +#endif +{ + XPA xpa = (XPA)call_data; + XPATclClientData xptr = (XPATclClientData)client_data; + Tcl_CmdInfo info; /* Info about command procedures */ + Tcl_Obj *objv[10]; /* Object vector for arguments */ + Tcl_Obj *resultPtr; /* The result object */ + int result; /* TCL_OK or TCL_ERROR */ + int object; + char tbuf[SZ_LINE]; + XCONST84 char *argv[10]; + char *s=NULL; + char *t=NULL; + char *cmd; + + /* make sure we have a callback */ + if( !xptr || !xptr->callback ){ + XPAError(xpa, "Invalid tcl command for xpa callback"); + return(-1); + } + /* set command name */ + cmd = xptr->callback; + + /* Map from the command name to a C procedure */ + if( !Tcl_GetCommandInfo(xptr->interp, cmd, &info) ){ + XPAError(xpa, "Unknown tcl command for xpa callback"); + return(-1); + } + + /* string-ize some values */ + snprintf(tbuf, SZ_LINE, "xpa_%p", xpa); + s = xstrdup(tbuf); + if( nargs > 4 ){ + snprintf(tbuf, SZ_LINE, "%d", len); + t = xstrdup(tbuf); + } + + /* package up argument values */ + object = info.isNativeObjectProc; + if (object) { + /* The object interface is preferred for this command */ + objv[0] = Tcl_NewStringObj(cmd, strlen(cmd)); + objv[1] = Tcl_NewStringObj(s, strlen(s)); + if( (xptr->client_data == NULL) || (*xptr->client_data == '\0') ) + objv[2] = Tcl_NewStringObj(NULLSTRING, strlen(NULLSTRING)); + else + objv[2] = Tcl_NewStringObj(xptr->client_data, strlen(xptr->client_data)); + if( (paramlist == NULL) || (*paramlist == '\0') ) + objv[3] = Tcl_NewStringObj(NULLSTRING, strlen(NULLSTRING)); + else + objv[3] = Tcl_NewStringObj(paramlist, strlen(paramlist)); + if( nargs > 4 ){ + if( (buf == NULL) || (*buf == '\0') || (len == 0) ) + objv[4] = Tcl_NewStringObj(NULLSTRING, strlen(NULLSTRING)); + else + objv[4] = Tcl_NewStringObj(buf, len); + objv[5] = Tcl_NewStringObj(t, strlen(t)); + } + } else { + argv[0] = cmd; + argv[1] = s; + argv[2] = xptr->client_data; + argv[3] = paramlist; + if( nargs > 4 ){ + argv[4] = buf; + argv[5] = t; + } + } + + /* reset before we make C call */ + Tcl_ResetResult(xptr->interp); + + /* + * Invoke the C procedure. + */ + if (object) { + result = (*info.objProc)(info.objClientData, xptr->interp, nargs, objv); + /* Get the string value from the result object */ + resultPtr = Tcl_GetObjResult(xptr->interp); + Tcl_SetResult(xptr->interp, Tcl_GetStringFromObj(resultPtr, NULL), + TCL_VOLATILE); + } else { + result = (*info.proc)(info.clientData, xptr->interp, nargs, argv); + } + + /* clean up */ + if( s ) xfree(s); + if( t ) xfree(t); + + /* translate Tcl status into XPA status */ + if( result == TCL_OK ){ + return(0); + } + else{ + s = (char *)Tcl_GetStringResult(xptr->interp); + if( !strncmp(s, "XPA$ERROR: ", 11) ) + s += 11; + XPAError(xpa, s); + return(-1); + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPATclReceive + * + * Purpose: receive handler for access points written in tcl + * execute the tcl receive command with xpa arguments + * used instead of Tcl_Eval so we can avoid interpreting either + * paramlist or buf + * + * + * Returns: 0 on success, -1 on failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPATclReceive (void *client_data, void *call_data, char *paramlist, + char *buf, size_t len) +#else +static int XPATclReceive(client_data, call_data, paramlist, buf, len) + void *client_data; + void *call_data; + char *paramlist; + char *buf; + size_t len; +#endif +{ + return(XPATclHandler(client_data, call_data, paramlist, buf, len, 6)); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPATclSend + * + * Purpose: send handler for access points written in tcl + * + * Returns: 0 on success, -1 on failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPATclSend (void *client_data, void *call_data, char *paramlist, + char **buf, size_t *len) +#else +static int XPATclSend(client_data, call_data, paramlist, buf, len) + void *client_data; + void *call_data; + char *paramlist; + char **buf; + size_t *len; +#endif +{ + return(XPATclHandler(client_data, call_data, paramlist, NULL, 0, 4)); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPATclInfo + * + * Purpose: info handler for access points written in tcl + * + * Returns: 0 on success, -1 on failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPATclInfo (void *client_data, void *call_data, char *paramlist) +#else +static int XPATclInfo(client_data, call_data, paramlist) + void *client_data; + void *call_data; + char *paramlist; +#endif +{ + return(XPATclHandler(client_data, call_data, paramlist, NULL, 0, 4)); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPANew_Tcl + * + * Purpose: Tcl binding to XPANew procedure + * + * Tcl call: + * + * xpanew class name help sproc sdata smode rproc rdata rmode + * + * use the empty string to specify NULL arguments + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPANew_Tcl(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +#else +static int XPANew_Tcl(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +#endif +{ + char *xclass; + char *name; + char *help; + char *send_cb; + char *sdata; + char *smode; + char *rec_cb; + char *rdata; + char *rmode; + char tbuf[SZ_LINE]; + XPA xpa; + SendCb sproc; + ReceiveCb rproc; + XPATclClientData sptr; + XPATclClientData rptr; + Tcl_Obj *resultPtr; + + /* make sure argument count is correct */ + if( objc != 10 ){ + Tcl_WrongNumArgs(interp, 1, objv, + "class name help sproc sdata smode rproc rdata rmode"); + return(TCL_ERROR); + } + + /* get arguments as strings */ + xclass = Tcl_GetStringFromObj(objv[1], NULL); + name = Tcl_GetStringFromObj(objv[2], NULL); + help = Tcl_GetStringFromObj(objv[3], NULL); + send_cb = Tcl_GetStringFromObj(objv[4], NULL); + sdata = Tcl_GetStringFromObj(objv[5], NULL); + smode = Tcl_GetStringFromObj(objv[6], NULL); + rec_cb = Tcl_GetStringFromObj(objv[7], NULL); + rdata = Tcl_GetStringFromObj(objv[8], NULL); + rmode = Tcl_GetStringFromObj(objv[9], NULL); + + /* this will hold the result */ + resultPtr = Tcl_GetObjResult(interp); + + /* set up callback procedures */ + if( ((send_cb == NULL) || (*send_cb == '\0') ) ){ + sproc = NULL; + sptr = NULL; + } + else{ + sproc = XPATclSend; + sptr = (XPATclClientData)xcalloc(1, sizeof(XPATclClientDataRec)); + sptr->interp = interp; + sptr->callback = xstrdup(send_cb); + sptr->client_data = xstrdup(sdata); + } + if( ((rec_cb == NULL) || (*rec_cb == '\0') ) ){ + rproc = NULL; + rptr = NULL; + } + else{ + rproc = XPATclReceive; + rptr = (XPATclClientData)xcalloc(1, sizeof(XPATclClientDataRec)); + rptr->interp = interp; + rptr->callback = xstrdup(rec_cb); + rptr->client_data = xstrdup(rdata); + } + + /* make sure we have either a send or receive callback */ + if( !sproc && !rproc ){ + Tcl_SetStringObj(resultPtr, + "XPA$ERROR: xpanew requires send_cb or rec_cb (or both)", -1); + return(TCL_ERROR); + } + + /* set up the tcl handler for the xpa access point */ + xpa = XPANew(xclass, name, help, sproc, sptr, smode, rproc, rptr, rmode); + if( xpa == NULL ){ + Tcl_SetStringObj(resultPtr, + "XPA$ERROR: could not create XPA access point", -1); + return(TCL_ERROR); + } + else{ + /* add this xpa to the Tcl event loop */ + XPATclAddInput(xpa); + /* return xpa address to tcl in a string */ + snprintf(tbuf, SZ_LINE, "xpa_%p", xpa); + Tcl_SetStringObj(resultPtr, tbuf, -1); + return(TCL_OK); + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAFree_Tcl + * + * Purpose: Tcl binding to XPAFree procedure + * + * Tcl call: + * + * xpafree xpa + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPAFree_Tcl(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +#else +static int XPAFree_Tcl(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +#endif +{ + XPA xpa; + XPATclClientData ptr; + + /* make sure argument count is correct */ + if( objc != 2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "xpa"); + return(TCL_ERROR); + } + + /* get xpa, which is always arg 1 */ + if( Tcl_GetXPAFromObj(interp, objv[1], TY_SERVER, &xpa) != TCL_OK){ + return(TCL_ERROR); + } + + /* reset error/result condition */ + Tcl_ResetResult(interp); + + /* free the associated tcl record, stored in the client data */ + if( xpa->send_data ){ + ptr = (XPATclClientData)xpa->send_data; + if( ptr->callback ) xfree( ptr->callback); + if( ptr->client_data ) xfree( ptr->client_data); + xfree(xpa->send_data); + } + if( xpa->receive_data ){ + ptr = (XPATclClientData)xpa->receive_data; + if( ptr->callback ) xfree( ptr->callback); + if( ptr->client_data ) xfree( ptr->client_data); + xfree(xpa->receive_data); + } + if( xpa->info_data ){ + ptr = (XPATclClientData)xpa->info_data; + if( ptr->callback ) xfree( ptr->callback); + if( ptr->client_data ) xfree( ptr->client_data); + xfree(xpa->info_data); + } + + /* call the XPAFree routine */ + XPAFree(xpa); + return(TCL_OK); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAInfoNew_Tcl + * + * Purpose: Tcl binding to XPAInfoNew procedure + * + * Tcl call: + * + * xpanew class name help iproc idata imode + * + * use the empty string to specify NULL arguments + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPAInfoNew_Tcl(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +#else +static int XPAInfoNew_Tcl(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +#endif +{ + char *xclass; + char *name; + char *info_cb; + char *idata; + char *imode; + char tbuf[SZ_LINE]; + XPA xpa; + InfoCb iproc; + XPATclClientData iptr; + Tcl_Obj *resultPtr; + + /* make sure argument count is correct */ + if( objc != 6 ){ + Tcl_WrongNumArgs(interp, 1, objv, + "class name iproc idata imode"); + return(TCL_ERROR); + } + + /* get arguments as strings */ + xclass = Tcl_GetStringFromObj(objv[1], NULL); + name = Tcl_GetStringFromObj(objv[2], NULL); + info_cb = Tcl_GetStringFromObj(objv[3], NULL); + idata = Tcl_GetStringFromObj(objv[4], NULL); + imode = Tcl_GetStringFromObj(objv[5], NULL); + + /* this will hold the result */ + resultPtr = Tcl_GetObjResult(interp); + + /* set up callback procedures */ + if( info_cb == NULL ){ + Tcl_SetStringObj(resultPtr, + "XPA$ERROR: xpainfonew requires info_cb", -1); + return(TCL_ERROR); + } + else{ + iproc = XPATclInfo; + iptr = (XPATclClientData)xcalloc(1, sizeof(XPATclClientDataRec)); + iptr->interp = interp; + iptr->callback = xstrdup(info_cb); + iptr->client_data = xstrdup(idata); + } + + /* set up the tcl handler for the xpa access point */ + xpa = XPAInfoNew(xclass, name, iproc, iptr, imode); + if( xpa == NULL ){ + Tcl_SetStringObj(resultPtr, + "XPA$ERROR: could not create XPA info access point", -1); + return(TCL_ERROR); + } + else{ + /* add this xpa to the Tcl event loop */ + XPATclAddInput(xpa); + /* return xpa address to tcl in a string */ + snprintf(tbuf, SZ_LINE, "xpa_%p", xpa); + Tcl_SetStringObj(resultPtr, tbuf, -1); + return(TCL_OK); + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPACmdNew_Tcl + * + * Purpose: Tcl binding to XPACmdNew procedure + * + * Tcl call: + * + * xpacmdnew class name + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPACmdNew_Tcl(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +#else +static int XPACmdNew_Tcl(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +#endif +{ + char *xclass; + char *name; + char tbuf[SZ_LINE]; + XPA xpa; + Tcl_Obj *resultPtr; + + /* make sure argument count is correct */ + if( objc != 3 ){ + Tcl_WrongNumArgs(interp, 1, objv, "class name"); + return(TCL_ERROR); + } + + /* get arguments as strings */ + xclass = Tcl_GetStringFromObj(objv[1], NULL); + name = Tcl_GetStringFromObj(objv[2], NULL); + + /* this will hold the result */ + resultPtr = Tcl_GetObjResult(interp); + + /* set up the tcl handler for the xpa access point */ + if( (xpa = XPACmdNew(xclass, name)) == NULL ){ + Tcl_SetStringObj(resultPtr, + "XPA$ERROR: could not create XPA command access point", -1); + return(TCL_ERROR); + } + else{ + /* add this xpa to the Tcl event loop */ + XPATclAddInput(xpa); + /* return xpa address to tcl in a string */ + snprintf(tbuf, SZ_LINE, "xpa_%p", xpa); + Tcl_SetStringObj(resultPtr, tbuf, -1); + return(TCL_OK); + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPACmdAdd_Tcl + * + * Purpose: Tcl binding to XPACmdAdd procedure + * + * Tcl call: + * + * xpacmdadd xpa name help sproc sdata smode rproc rdata rmode + * + * use the empty string to specify NULL arguments + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPACmdAdd_Tcl(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +#else +static int XPACmdAdd_Tcl(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +#endif +{ + char *name; + char *help; + char *send_cb; + char *sdata; + char *smode; + char *rec_cb; + char *rdata; + char *rmode; + char tbuf[SZ_LINE]; + XPA xpa; + XPACmd xpacmd; + SendCb sproc; + ReceiveCb rproc; + XPATclClientData sptr; + XPATclClientData rptr; + Tcl_Obj *resultPtr; + + /* make sure argument count is correct */ + if( objc != 10 ){ + Tcl_WrongNumArgs(interp, 1, objv, + "class name help sproc sdata smode rproc rdata rmode"); + return(TCL_ERROR); + } + + /* get xpa, which is always arg 1 */ + if( Tcl_GetXPAFromObj(interp, objv[1], TY_SERVER, &xpa) != TCL_OK){ + return(TCL_ERROR); + } + + name = Tcl_GetStringFromObj(objv[2], NULL); + help = Tcl_GetStringFromObj(objv[3], NULL); + send_cb = Tcl_GetStringFromObj(objv[4], NULL); + sdata = Tcl_GetStringFromObj(objv[5], NULL); + smode = Tcl_GetStringFromObj(objv[6], NULL); + rec_cb = Tcl_GetStringFromObj(objv[7], NULL); + rdata = Tcl_GetStringFromObj(objv[8], NULL); + rmode = Tcl_GetStringFromObj(objv[9], NULL); + + /* this will hold the result */ + resultPtr = Tcl_GetObjResult(interp); + + /* set up callback procedures */ + if( ((send_cb == NULL) || (*send_cb == '\0') ) ){ + sproc = NULL; + sptr = NULL; + } + else{ + sproc = XPATclSend; + sptr = (XPATclClientData)xcalloc(1, sizeof(XPATclClientDataRec)); + sptr->interp = interp; + sptr->callback = xstrdup(send_cb); + sptr->client_data = xstrdup(sdata); + } + if( ((rec_cb == NULL) || (*rec_cb == '\0') ) ){ + rproc = NULL; + rptr = NULL; + } + else{ + rproc = XPATclReceive; + rptr = (XPATclClientData)xcalloc(1, sizeof(XPATclClientDataRec)); + rptr->interp = interp; + rptr->callback = xstrdup(rec_cb); + rptr->client_data = xstrdup(rdata); + } + + /* make sure we have either a send or receive callback */ + if( !sproc && !rproc ){ + Tcl_SetStringObj(resultPtr, + "XPA$ERROR: xpacmdadd requires send_cb or rec_cb (or both)", -1); + return(TCL_ERROR); + } + + /* set up the tcl handler for the xpa access point */ + xpacmd = XPACmdAdd(xpa, name, help, sproc, sptr, smode, rproc, rptr, rmode); + if( xpacmd == NULL ){ + Tcl_SetStringObj(resultPtr, "XPA$ERROR: could not create XPA command", -1); + return(TCL_ERROR); + } + else{ + /* return xpa address to tcl in a string */ + snprintf(tbuf, SZ_LINE, "xpacmd_%p", xpacmd); + Tcl_SetStringObj(resultPtr, tbuf, -1); + return(TCL_OK); + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPACmdDel_Tcl + * + * Purpose: Tcl binding to XPACmdDel procedure + * + * Tcl call: + * + * xpacmddel xpa cmd + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPACmdDel_Tcl(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +#else +static int XPACmdDel_Tcl(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +#endif +{ + void *lval; + char *s; + XPA xpa; + XPACmd cmd; + Tcl_Obj *resultPtr; + + /* make sure argument count is correct */ + if( objc != 3 ){ + Tcl_WrongNumArgs(interp, 1, objv, "xpa cmd"); + return(TCL_ERROR); + } + + /* get result pointer */ + resultPtr = Tcl_GetObjResult(interp); + + /* get xpa, which is always arg 1 */ + if( Tcl_GetXPAFromObj(interp, objv[1], TY_SERVER, &xpa) != TCL_OK){ + return(TCL_ERROR); + } + + /* get xpacmd, which is always arg 2 */ + if( (s = Tcl_GetStringFromObj(objv[2], NULL)) == NULL ){ + return(TCL_ERROR); + } + if( strncmp(s, "xpacmd_", 7) || (sscanf(&(s[7]), "%p", &lval) != 1) ){ + Tcl_SetStringObj(resultPtr, "XPA$ERROR: invalid xpacmd handle", -1); + return(TCL_ERROR); + } + cmd = (XPACmd)lval; + + /* reset error/result condition */ + Tcl_ResetResult(interp); + + /* call the XPACmdDel routine */ + if( XPACmdDel(xpa, cmd) == 0 ){ + /* free the associated tcl record, stored in the client data */ + if( cmd->send_data ) xfree(cmd->send_data); + if( cmd->receive_data ) xfree(cmd->receive_data); + return(TCL_OK); + } + else{ + resultPtr = Tcl_GetObjResult(interp); + Tcl_SetStringObj(resultPtr, "XPA$ERROR: could not delete xpa cmd", -1); + return(TCL_ERROR); + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPARec_Tcl + * + * Purpose: Tcl binding to retrieve info from the xpa struct + * + * Tcl call: + * + * set val [xparec xpa <option>] + * + * where option can be one of the following: + * + * name + * class + * method + * cmdfd + * datafd +#ifndef HAVE_CYGWIN + * cmdchan + * datachan +#endif + * sendian + * cendian + * version + * + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPARec_Tcl(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +#else +static int XPARec_Tcl(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +#endif +{ +#ifndef HAVE_CYGWIN + Tcl_Channel chan; +#endif + static XCONST84 char *subCmds[] = { + "cendian", + "class", +#ifndef HAVE_CYGWIN + "cmdchan", +#endif + "cmdfd", +#ifndef HAVE_CYGWIN + "datachan", +#endif + "datafd", + "method", + "name", + "sendian", + "version", + (char *) NULL}; + enum ISubCmdIdx { + ICendianIdx, + IClassIdx, +#ifndef HAVE_CYGWIN + ICmdChanIdx, +#endif + ICmdFdIdx, +#ifndef HAVE_CYGWIN + IDataChanIdx, +#endif + IDataFdIdx, + IMethodIdx, + INameIdx, + ISendianIdx, + IVersionIdx + } index; + XPA xpa; + int result; + char tbuf[SZ_LINE]; + + /* we always have 3 args: xparec $xpa [option] */ + if (objc != 3) { + Tcl_WrongNumArgs(interp, 1, objv, "xpa option"); + return TCL_ERROR; + } + + /* get sub-command index */ + if( (result = Tcl_GetIndexFromObj(interp, objv[2], subCmds, "option", 0, + (int *)&index)) != TCL_OK ){ + return result; + } + + /* get xpa, which is always arg 1 */ + if( (result=Tcl_GetXPAFromObj(interp, objv[1], TY_SERVER, &xpa)) != TCL_OK){ + /* valid xpa is required, except for version */ + if( index != IVersionIdx ) + return(TCL_ERROR); + } + + /* process sub-command */ + switch (index) { + case ICendianIdx: + Tcl_SetResult(interp, (char *)xpa_cendian(xpa), TCL_VOLATILE); + result = TCL_OK; + break; + case IClassIdx: + Tcl_SetResult(interp, xpa_class(xpa), TCL_VOLATILE); + result = TCL_OK; + break; +#ifndef HAVE_CYGWIN + case ICmdChanIdx: + snprintf(tbuf, SZ_LINE, "sock%d", xpa_cmdfd(xpa)); + /* make sure we have a valid OS socket fd */ + if( xpa_cmdfd(xpa) < 0 ){ + Tcl_SetResult(interp, "none", TCL_STATIC); + result = TCL_OK; + } + /* see if this socket already is defined as a tcl variable */ + else if( Tcl_GetChannel(interp, tbuf, NULL) != NULL ){ + Tcl_SetResult(interp, tbuf, TCL_VOLATILE); + result = TCL_OK; + } + /* create new tcl variable for this socket */ + else{ + /* create a tcl channel corresponding to the xpa socket */ + if( !(chan = Tcl_MakeTcpClientChannel((ClientData)(uintptr_t)xpa_cmdfd(xpa))) ){ + Tcl_SetResult(interp, "XPA$ERROR: could not map XPA cmdfd to tcl", + TCL_STATIC); + result = TCL_ERROR; + } + else{ + /* hold a reference to this channel outside tcl */ + Tcl_RegisterChannel(NULL, chan); + /* register this channel with tcl */ + Tcl_RegisterChannel(interp, chan); + /* make this Tcl channel unbuffered, so user does not have to flush */ + Tcl_SetChannelOption(interp, chan, "-buffering", "none"); + /* return name so that it can be used by tcl */ + Tcl_SetResult(interp, (char *)Tcl_GetChannelName(chan), TCL_VOLATILE); + result = TCL_OK; + } + } + break; +#endif + case ICmdFdIdx: + if( xpa_cmdfd(xpa) < 0 ) + strcpy(tbuf, "none"); + else + snprintf(tbuf, SZ_LINE, "%d", xpa_cmdfd(xpa)); + Tcl_SetResult(interp, tbuf, TCL_VOLATILE); + result = TCL_OK; + break; +#ifndef HAVE_CYGWIN + case IDataChanIdx: + snprintf(tbuf, SZ_LINE, "sock%d", xpa_datafd(xpa)); + /* make sure we have a valid OS socket fd */ + if( xpa_datafd(xpa) < 0 ){ + Tcl_SetResult(interp, "none", TCL_STATIC); + result = TCL_OK; + } + /* see if this socket already is defined as a tcl variable */ + else if( Tcl_GetChannel(interp, tbuf, NULL) != NULL ){ + Tcl_SetResult(interp, tbuf, TCL_VOLATILE); + result = TCL_OK; + } + /* create new tcl variable for this socket */ + else{ + if( !(chan = Tcl_MakeTcpClientChannel((ClientData)(uintptr_t)xpa_datafd(xpa))) ){ + Tcl_SetResult(interp, "XPA$ERROR: could not map XPA datafd to tcl", + TCL_STATIC); + result = TCL_ERROR; + } + else{ + /* hold a reference to this channel outside tcl */ + Tcl_RegisterChannel(NULL, chan); + /* register this channel with tcl */ + Tcl_RegisterChannel(interp, chan); + /* make this Tcl channel unbuffered, so user does not have to flush */ + Tcl_SetChannelOption(interp, chan, "-buffering", "none"); + /* return name so that it can be used by tcl */ + Tcl_SetResult(interp, (char *)Tcl_GetChannelName(chan), TCL_VOLATILE); + result = TCL_OK; + } + } + break; +#endif + case IDataFdIdx: + if( xpa_datafd(xpa) < 0 ) + strcpy(tbuf, "none"); + else + snprintf(tbuf, SZ_LINE, "%d", xpa_datafd(xpa)); + Tcl_SetResult(interp, tbuf, TCL_VOLATILE); + result = TCL_OK; + break; + case IMethodIdx: + Tcl_SetResult(interp, xpa_method(xpa), TCL_VOLATILE); + result = TCL_OK; + break; + case INameIdx: + Tcl_SetResult(interp, xpa_name(xpa), TCL_VOLATILE); + result = TCL_OK; + break; + case ISendianIdx: + Tcl_SetResult(interp, xpa_sendian(xpa), TCL_VOLATILE); + result = TCL_OK; + break; + case IVersionIdx: + snprintf(tbuf, SZ_LINE, "%s", XPA_VERSION); + Tcl_SetResult(interp, tbuf, TCL_VOLATILE); + result = TCL_OK; + break; + } + return result; +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPASetBuf_Tcl + * + * Purpose: Tcl binding to XPASetBuf procedure + * + * Tcl call: + * + * xpasetbuf xpa buf len + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPASetBuf_Tcl(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +#else +static int XPASetBuf_Tcl(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +#endif +{ + int error; + int len; + char *buf; + XPA xpa; + + /* make sure argument count is correct */ + if( objc < 3 ){ + Tcl_WrongNumArgs(interp, 1, objv, "xpa buf len"); + return(TCL_ERROR); + } + + /* get xpa, which is always arg 1 */ + if( Tcl_GetXPAFromObj(interp, objv[1], TY_SERVER, &xpa) != TCL_OK){ + return(TCL_ERROR); + } + + /* get buf */ + buf = Tcl_GetStringFromObj(objv[2], &len); + /* get len if specified */ + if( objc >= 4 ){ + if( (error = Tcl_GetIntFromObj(interp, objv[3], &len)) != TCL_OK ) + return(error); + } + /* copy buffer to the xpa struct */ + XPASetBuf(xpa, buf, len, 1); + /* return status */ + return(TCL_OK); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAOpen_Tcl + * + * Purpose: Tcl binding to XPAOpen procedure + * + * Tcl call: + * + * xpaopen mode + * + * mode currently is NULL + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPAOpen_Tcl(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +#else +static int XPAOpen_Tcl(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +#endif +{ + char *mode; + char tbuf[SZ_LINE]; + XPA xpa; + Tcl_Obj *resultPtr; + + /* make sure argument count is correct */ + if( objc != 2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "mode"); + return(TCL_ERROR); + } + + /* get arguments as strings */ + mode = Tcl_GetStringFromObj(objv[1], NULL); + + /* this will hold the result */ + resultPtr = Tcl_GetObjResult(interp); + + /* set up the tcl handler for the xpa access point */ + xpa = XPAOpen(mode); + if( xpa == NULL ){ + Tcl_SetStringObj(resultPtr, + "XPA$ERROR: could not open XPA", -1); + return(TCL_ERROR); + } + else{ + /* return xpa address to tcl in a string */ + snprintf(tbuf, SZ_LINE, "xpa_%p", xpa); + Tcl_SetStringObj(resultPtr, tbuf, -1); + return(TCL_OK); + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAClose_Tcl + * + * Purpose: Tcl binding to XPAClose procedure + * + * Tcl call: + * + * xpaclose xpa + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPAClose_Tcl(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +#else +static int XPAClose_Tcl(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +#endif +{ + XPA xpa; + + /* make sure argument count is correct */ + if( objc != 2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "xpa"); + return(TCL_ERROR); + } + + /* get xpa, which is always arg 1 */ + if( Tcl_GetXPAFromObj(interp, objv[1], TY_CLIENT, &xpa) != TCL_OK){ + return(TCL_ERROR); + } + + /* reset error/result condition */ + Tcl_ResetResult(interp); + + /* call the XPAClose routine */ + XPAClose(xpa); + return(TCL_OK); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAGet_Tcl + * + * Purpose: Tcl binding to XPAGet procedure + * + * Tcl call: + * + * set got [xpaget xpa template paramlist mode bufs lens names errs n] + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPAGet_Tcl(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +#else +static int XPAGet_Tcl(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +#endif +{ + XPA xpa; + int got; + int n; + int i; + size_t *clens=NULL; + char *xpastr; + char *tmpl; + char *paramlist; + char *mode; + /* char *bufs; */ + /* char *lens; */ + char *names; + char *errs; + char **cbufs=NULL; + char **cnames=NULL; + char **cerrs=NULL; + Tcl_Obj *resultPtr; + Tcl_Obj *nullPtr; + Tcl_Obj *bufsPtr; + Tcl_Obj *lensPtr; + Tcl_Obj *namesPtr; + Tcl_Obj *errsPtr; + Tcl_Obj **bufsObjv; + Tcl_Obj **lensObjv; + Tcl_Obj **namesObjv=NULL; + Tcl_Obj **errsObjv=NULL; + + /* make sure argument count is correct */ + if( objc != 10 ){ + Tcl_WrongNumArgs(interp, 1, objv, + "xpa template paramlist mode bufs lens names errs n"); + return(TCL_ERROR); + } + + /* get result pointer */ + resultPtr = Tcl_GetObjResult(interp); + + /* get xpa struct pointer, which might be NULL */ + xpastr = Tcl_GetStringFromObj(objv[1], NULL); + if( TCL_NULLSTR(xpastr) ) + xpa = NULL; + else{ + /* get xpa, which is always arg 1 */ + if( Tcl_GetXPAFromObj(interp, objv[1], TY_CLIENT, &xpa) != TCL_OK){ + Tcl_SetStringObj(resultPtr, "XPA$ERROR: invalid xpa client handle", -1); + return(TCL_ERROR); + } + } + + /* get other args */ + tmpl = Tcl_GetStringFromObj(objv[2], NULL); + paramlist = Tcl_GetStringFromObj(objv[3], NULL); + mode = Tcl_GetStringFromObj(objv[4], NULL); + /* bufs = Tcl_GetStringFromObj(objv[5], NULL); */ + /* lens = Tcl_GetStringFromObj(objv[6], NULL); */ + names = Tcl_GetStringFromObj(objv[7], NULL); + errs = Tcl_GetStringFromObj(objv[8], NULL); + if( (Tcl_GetIntFromObj(interp, objv[9], &n) != TCL_OK) || (n < 1) ){ + n = 1; + } + + /* allocate return buffers */ + cbufs = (char **)xcalloc(n, sizeof(char *)); + bufsObjv = (Tcl_Obj **)xcalloc(n, sizeof(Tcl_Obj *)); + clens = (size_t *)xcalloc(n, sizeof(size_t)); + lensObjv = (Tcl_Obj **)xcalloc(n, sizeof(Tcl_Obj *)); + if( !TCL_NULLSTR(names) ){ + cnames = (char **)xcalloc(n, sizeof(char *)); + namesObjv = (Tcl_Obj **)xcalloc(n, sizeof(Tcl_Obj *)); + } + if( !TCL_NULLSTR(errs) ){ + cerrs = (char **)xcalloc(n, sizeof(char *)); + errsObjv = (Tcl_Obj **)xcalloc(n, sizeof(Tcl_Obj *)); + } + + /* reset before we make C call */ + Tcl_ResetResult(interp); + + /* make the XPA C call */ + got = XPAGet(xpa, tmpl, paramlist, mode, cbufs, clens, cnames, cerrs, n); + + /* if we got anything, fill in the blanks */ + if( got > 0 ){ + /* generate a Tcl object for each return argument */ + for(i=0; i<got; i++){ + bufsObjv[i] = Tcl_NewObj(); + Tcl_SetStringObj(bufsObjv[i], cbufs[i], clens[i]); + + lensObjv[i] = Tcl_NewObj(); + Tcl_SetIntObj(lensObjv[i], clens[i]); + + if( cnames ){ + namesObjv[i] = Tcl_NewObj(); + Tcl_SetStringObj(namesObjv[i], cnames[i], + cnames[i] ? strlen(cnames[i]) : 0); + } + + if( cerrs ){ + errsObjv[i] = Tcl_NewObj(); + Tcl_SetStringObj(errsObjv[i], cerrs[i], + cerrs[i] ? strlen(cerrs[i]) : 0); + } + } + /* make lists from the return arguments and set the return variables */ + bufsPtr = Tcl_NewObj(); + Tcl_SetListObj(bufsPtr, got, bufsObjv); + Tcl_ObjSetVar2(interp, objv[5], NULL, bufsPtr, TCL_PARSE_PART1); + + lensPtr = Tcl_NewObj(); + Tcl_SetListObj(lensPtr, got, lensObjv); + Tcl_ObjSetVar2(interp, objv[6], NULL, lensPtr, TCL_PARSE_PART1); + + if( cnames ){ + namesPtr = Tcl_NewObj(); + Tcl_SetListObj(namesPtr, got, namesObjv); + Tcl_ObjSetVar2(interp, objv[7], NULL, namesPtr, TCL_PARSE_PART1); + } + + if( cerrs ){ + errsPtr = Tcl_NewObj(); + Tcl_SetListObj(errsPtr, got, errsObjv); + Tcl_ObjSetVar2(interp, objv[8], NULL, errsPtr, TCL_PARSE_PART1); + } + } + else{ + nullPtr = Tcl_NewObj(); + Tcl_SetStringObj(nullPtr, "", -1); + Tcl_ObjSetVar2(interp, objv[5], NULL, nullPtr, TCL_PARSE_PART1); + Tcl_ObjSetVar2(interp, objv[6], NULL, nullPtr, TCL_PARSE_PART1); + if( cnames ) + Tcl_ObjSetVar2(interp, objv[7], NULL, nullPtr, TCL_PARSE_PART1); + if( cerrs ) + Tcl_ObjSetVar2(interp, objv[8], NULL, nullPtr, TCL_PARSE_PART1); + } + + /* free up space */ + for(i=0; i<got; i++){ + if( cbufs[i] ) xfree((char *)cbufs[i]); + if( cnames[i] ) xfree((char *)cnames[i]); + if( cerrs[i] ) xfree((char *)cerrs[i]); + } + if( cbufs ) xfree((char *)cbufs); + if( clens ) xfree((char *)clens); + if( cnames ) xfree((char *)cnames); + if( cerrs ) xfree((char *)cerrs); + if( bufsObjv ) xfree((char *)bufsObjv); + if( lensObjv ) xfree((char *)lensObjv); + if( namesObjv ) xfree((char *)namesObjv); + if( errsObjv ) xfree((char *)errsObjv); + + /* return the number of accesses as the tcl function result */ + resultPtr = Tcl_GetObjResult(interp); + Tcl_SetIntObj(resultPtr, got); + + /* return status */ + return(TCL_OK); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAGetFd_Tcl + * + * Purpose: Tcl binding to XPAGetFd procedure + * + * Tcl call: + * + * set got [xpaget xpa template paramlist mode chans names errs n] + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPAGetFd_Tcl(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +#else +static int XPAGetFd_Tcl(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +#endif +{ + XPA xpa; + int got; + int n; + int i; + int flag; + int *cfds; + char *xpastr; + char *tmpl; + char *paramlist; + char *mode; + char *names; + char *errs; + char **cnames=NULL; + char **cerrs=NULL; + Tcl_Obj *resultPtr; + Tcl_Obj *nullPtr; + Tcl_Obj *fdPtr; + Tcl_Obj *namesPtr; + Tcl_Obj *errsPtr; + Tcl_Obj **namesObjv=NULL; + Tcl_Obj **errsObjv=NULL; + Tcl_Channel chan; + + /* make sure argument count is correct */ + if( objc != 9 ){ + Tcl_WrongNumArgs(interp, 1, objv, + "xpa template paramlist mode chans names errs n"); + return(TCL_ERROR); + } + + /* get result pointer */ + resultPtr = Tcl_GetObjResult(interp); + + /* get xpa struct pointer, which might be NULL */ + xpastr = Tcl_GetStringFromObj(objv[1], NULL); + if( TCL_NULLSTR(xpastr) ) + xpa = NULL; + else{ + /* get xpa, which is always arg 1 */ + if( Tcl_GetXPAFromObj(interp, objv[1], TY_CLIENT, &xpa) != TCL_OK ){ + Tcl_SetStringObj(resultPtr, "XPA$ERROR: invalid xpa client handle", -1); + return(TCL_ERROR); + } + } + + /* get other args */ + tmpl = Tcl_GetStringFromObj(objv[2], NULL); + paramlist = Tcl_GetStringFromObj(objv[3], NULL); + mode = Tcl_GetStringFromObj(objv[4], NULL); + names = Tcl_GetStringFromObj(objv[6], NULL); + errs = Tcl_GetStringFromObj(objv[7], NULL); + if( (Tcl_GetIntFromObj(interp, objv[8], &n) != TCL_OK) || (n < 1) ){ + n = 1; + } + + /* get file descriptors */ + if( n < 0 ){ + cfds = (int *)xcalloc(1, sizeof(int)); + if( Tcl_ListObjIndex(interp, objv[5], 0, &fdPtr) != TCL_OK ){ + Tcl_SetStringObj(resultPtr, + "XPA$ERROR: invalid channel list passed to xpagetfd", -1); + return(TCL_ERROR); + } + else{ + chan = Tcl_GetChannel(interp, Tcl_GetStringFromObj(fdPtr, NULL), + &flag); + if( chan == NULL ){ + Tcl_SetStringObj(resultPtr, + "XPA$ERROR: invalid channel passed to xpagetfd", -1); + return(TCL_ERROR); + } + if( !(flag&TCL_WRITABLE) ){ + Tcl_SetStringObj(resultPtr, + "XPA$ERROR: non-writable channel passed to xpagetfd", -1); + return(TCL_ERROR); + } + Tcl_GetChannelHandle(chan, TCL_WRITABLE, (ClientData *)&(cfds[0])); + } + } + else{ + cfds = (int *)xcalloc(n, sizeof(int)); + for(i=0; i<n; i++){ + if( Tcl_ListObjIndex(interp, objv[5], i, &fdPtr) != TCL_OK ){ + Tcl_SetStringObj(resultPtr, + "XPA$ERROR: invalid channel list passed to xpagetfd", -1); + return(TCL_ERROR); + } + else{ + chan = Tcl_GetChannel(interp, Tcl_GetStringFromObj(fdPtr, NULL), + &flag); + if( chan == NULL ){ + Tcl_SetStringObj(resultPtr, + "XPA$ERROR: invalid channel passed to xpagetfd", -1); + return(TCL_ERROR); + } + if( !(flag&TCL_WRITABLE) ){ + Tcl_SetStringObj(resultPtr, + "XPA$ERROR: non-writable channel passed to xpagetfd", -1); + return(TCL_ERROR); + } + Tcl_GetChannelHandle(chan, TCL_WRITABLE, (ClientData *)&(cfds[i])); + } + } + } + + /* allocate return buffers */ + if( !TCL_NULLSTR(names) ){ + cnames = (char **)xcalloc(n, sizeof(char *)); + namesObjv = (Tcl_Obj **)xcalloc(n, sizeof(Tcl_Obj *)); + } + if( !TCL_NULLSTR(errs) ){ + cerrs = (char **)xcalloc(n, sizeof(char *)); + errsObjv = (Tcl_Obj **)xcalloc(n, sizeof(Tcl_Obj *)); + } + + /* reset before we make C call */ + Tcl_ResetResult(interp); + + /* make the XPA C call */ + got = XPAGetFd(xpa, tmpl, paramlist, mode, cfds, cnames, cerrs, n); + + /* if we got anything, fill in the blanks */ + if( got > 0 ){ + /* generate a Tcl object for each return argument */ + for(i=0; i<got; i++){ + if( cnames ){ + namesObjv[i] = Tcl_NewObj(); + Tcl_SetStringObj(namesObjv[i], cnames[i], + cnames[i] ? strlen(cnames[i]) : 0); + } + + if( cerrs ){ + errsObjv[i] = Tcl_NewObj(); + Tcl_SetStringObj(errsObjv[i], cerrs[i], + cerrs[i] ? strlen(cerrs[i]) : 0); + } + } + /* make lists from the return arguments and set the return variables */ + if( cnames ){ + namesPtr = Tcl_NewObj(); + Tcl_SetListObj(namesPtr, got, namesObjv); + Tcl_ObjSetVar2(interp, objv[6], NULL, namesPtr, TCL_PARSE_PART1); + } + if( cerrs ){ + errsPtr = Tcl_NewObj(); + Tcl_SetListObj(errsPtr, got, errsObjv); + Tcl_ObjSetVar2(interp, objv[7], NULL, errsPtr, TCL_PARSE_PART1); + } + } + else{ + nullPtr = Tcl_NewObj(); + Tcl_SetStringObj(nullPtr, "", -1); + if( cnames ) + Tcl_ObjSetVar2(interp, objv[6], NULL, nullPtr, TCL_PARSE_PART1); + if( cerrs ) + Tcl_ObjSetVar2(interp, objv[7], NULL, nullPtr, TCL_PARSE_PART1); + } + + /* free up space */ + for(i=0; i<got; i++){ + if( cnames[i] ) xfree((char *)cnames[i]); + if( cerrs[i] ) xfree((char *)cerrs[i]); + } + if( cfds ) xfree((char *)cfds); + if( cnames ) xfree((char *)cnames); + if( cerrs ) xfree((char *)cerrs); + if( namesObjv ) xfree((char *)namesObjv); + if( errsObjv ) xfree((char *)errsObjv); + + /* return the number of accesses as the tcl function result */ + Tcl_SetIntObj(resultPtr, got); + + /* return status */ + return(TCL_OK); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPASet_Tcl + * + * Purpose: Tcl binding to XPASet procedure + * + * Tcl call: + * + * set got [xpaset xpa template paramlist mode buf len names errs n] + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPASet_Tcl(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +#else +static int XPASet_Tcl(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +#endif +{ + XPA xpa; + int got; + int n; + int i; + int blen; + int len; + char *xpastr; + char *tmpl; + char *paramlist; + char *mode; + char *buf; + char *names; + char *errs; + char **cnames=NULL; + char **cerrs=NULL; + Tcl_Obj *resultPtr; + Tcl_Obj *nullPtr; + Tcl_Obj *namesPtr; + Tcl_Obj *errsPtr; + Tcl_Obj **namesObjv=NULL; + Tcl_Obj **errsObjv=NULL; + + /* make sure argument count is correct */ + if( objc != 10 ){ + Tcl_WrongNumArgs(interp, 1, objv, + "xpa template paramlist mode buf len names errs n"); + return(TCL_ERROR); + } + + /* get result pointer */ + resultPtr = Tcl_GetObjResult(interp); + + /* get xpa struct pointer, which might be NULL */ + xpastr = Tcl_GetStringFromObj(objv[1], NULL); + if( TCL_NULLSTR(xpastr) ) + xpa = NULL; + else{ + /* get xpa, which is always arg 1 */ + if( Tcl_GetXPAFromObj(interp, objv[1], TY_CLIENT, &xpa) != TCL_OK ){ + Tcl_SetStringObj(resultPtr, "XPA$ERROR: invalid xpa client handle", -1); + return(TCL_ERROR); + } + } + + /* get other args */ + tmpl = Tcl_GetStringFromObj(objv[2], NULL); + paramlist = Tcl_GetStringFromObj(objv[3], NULL); + mode = Tcl_GetStringFromObj(objv[4], NULL); + buf = Tcl_GetStringFromObj(objv[5], &blen); + if( (Tcl_GetIntFromObj(interp, objv[6], &len) != TCL_OK) || (len < 0) ){ + len = blen; + } + names = Tcl_GetStringFromObj(objv[7], NULL); + errs = Tcl_GetStringFromObj(objv[8], NULL); + if( (Tcl_GetIntFromObj(interp, objv[9], &n) != TCL_OK) || (n < 1) ){ + n = 1; + } + + /* allocate return buffers */ + if( !TCL_NULLSTR(names) ){ + cnames = (char **)xcalloc(n, sizeof(char *)); + namesObjv = (Tcl_Obj **)xcalloc(n, sizeof(Tcl_Obj *)); + } + if( !TCL_NULLSTR(errs) ){ + cerrs = (char **)xcalloc(n, sizeof(char *)); + errsObjv = (Tcl_Obj **)xcalloc(n, sizeof(Tcl_Obj *)); + } + + /* reset before we make C call */ + Tcl_ResetResult(interp); + + /* make the XPA C call */ + got = XPASet(xpa, tmpl, paramlist, mode, buf, len, cnames, cerrs, n); + + /* if we got anything, fill in the blanks */ + if( got > 0 ){ + /* generate a Tcl object for each return argument */ + for(i=0; i<got; i++){ + if( cnames ){ + namesObjv[i] = Tcl_NewObj(); + Tcl_SetStringObj(namesObjv[i], cnames[i], + cnames[i] ? strlen(cnames[i]) : 0); + } + if( cerrs ){ + errsObjv[i] = Tcl_NewObj(); + Tcl_SetStringObj(errsObjv[i], cerrs[i], + cerrs[i] ? strlen(cerrs[i]) : 0); + } + } + /* make lists from the return arguments and set the return variables */ + if( cnames ){ + namesPtr = Tcl_NewObj(); + Tcl_SetListObj(namesPtr, got, namesObjv); + Tcl_ObjSetVar2(interp, objv[7], NULL, namesPtr, TCL_PARSE_PART1); + } + if( cerrs ){ + errsPtr = Tcl_NewObj(); + Tcl_SetListObj(errsPtr, got, errsObjv); + Tcl_ObjSetVar2(interp, objv[8], NULL, errsPtr, TCL_PARSE_PART1); + } + } + else{ + nullPtr = Tcl_NewObj(); + Tcl_SetStringObj(nullPtr, "", -1); + if( cnames ) + Tcl_ObjSetVar2(interp, objv[7], NULL, nullPtr, TCL_PARSE_PART1); + if( cerrs ) + Tcl_ObjSetVar2(interp, objv[8], NULL, nullPtr, TCL_PARSE_PART1); + } + + /* free up space */ + for(i=0; i<got; i++){ + if( cnames[i] ) xfree((char *)cnames[i]); + if( cerrs[i] ) xfree((char *)cerrs[i]); + } + if( cnames ) xfree((char *)cnames); + if( cerrs ) xfree((char *)cerrs); + if( namesObjv ) xfree((char *)namesObjv); + if( errsObjv ) xfree((char *)errsObjv); + + /* return the number of accesses as the tcl function result */ + Tcl_SetIntObj(resultPtr, got); + + /* return status */ + return(TCL_OK); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPASetFd_Tcl + * + * Purpose: Tcl binding to XPASetFd procedure + * + * Tcl call: + * + * set got [xpasetfd xpa template paramlist mode chan names errs n] + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPASetFd_Tcl(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +#else +static int XPASetFd_Tcl(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +#endif +{ + XPA xpa; + int got; + int n; + int i; + int flag; + int fd; + char *xpastr; + char *tmpl; + char *paramlist; + char *mode; + char *names; + char *errs; + char **cnames=NULL; + char **cerrs=NULL; + Tcl_Obj *resultPtr; + Tcl_Obj *nullPtr; + Tcl_Obj *namesPtr; + Tcl_Obj *errsPtr; + Tcl_Obj **namesObjv=NULL; + Tcl_Obj **errsObjv=NULL; + Tcl_Channel chan; + + /* make sure argument count is correct */ + if( objc != 9 ){ + Tcl_WrongNumArgs(interp, 1, objv, + "xpa template paramlist mode chan names errs n"); + return(TCL_ERROR); + } + + /* get result pointer */ + resultPtr = Tcl_GetObjResult(interp); + + /* get xpa struct pointer, which might be NULL */ + xpastr = Tcl_GetStringFromObj(objv[1], NULL); + if( TCL_NULLSTR(xpastr) ) + xpa = NULL; + else{ + /* get xpa, which is always arg 1 */ + if( Tcl_GetXPAFromObj(interp, objv[1], TY_CLIENT, &xpa) != TCL_OK){ + Tcl_SetStringObj(resultPtr, "XPA$ERROR: invalid xpa client handle", -1); + return(TCL_ERROR); + } + } + + /* get other args */ + tmpl = Tcl_GetStringFromObj(objv[2], NULL); + paramlist = Tcl_GetStringFromObj(objv[3], NULL); + mode = Tcl_GetStringFromObj(objv[4], NULL); + names = Tcl_GetStringFromObj(objv[6], NULL); + errs = Tcl_GetStringFromObj(objv[7], NULL); + if( (Tcl_GetIntFromObj(interp, objv[8], &n) != TCL_OK) || (n < 1) ){ + n = 1; + } + + /* allocate return buffers */ + if( !TCL_NULLSTR(names) ){ + cnames = (char **)xcalloc(n, sizeof(char *)); + namesObjv = (Tcl_Obj **)xcalloc(n, sizeof(Tcl_Obj *)); + } + if( !TCL_NULLSTR(errs) ){ + cerrs = (char **)xcalloc(n, sizeof(char *)); + errsObjv = (Tcl_Obj **)xcalloc(n, sizeof(Tcl_Obj *)); + } + + /* get file descriptor */ + chan = Tcl_GetChannel(interp, Tcl_GetStringFromObj(objv[5], NULL), &flag); + if( chan == NULL ){ + Tcl_SetStringObj(resultPtr, + "XPA$ERROR: invalid channel passed to xpasetfd", -1); + return(TCL_ERROR); + } + if( !(flag&TCL_READABLE) ){ + Tcl_SetStringObj(resultPtr, + "XPA$ERROR: non-readable channel passed to xpasetfd", -1); + return(TCL_ERROR); + } + Tcl_GetChannelHandle(chan, TCL_READABLE, (ClientData *)&fd); + + /* reset before we make C call */ + Tcl_ResetResult(interp); + + /* make the XPA C call */ + got = XPASetFd(xpa, tmpl, paramlist, mode, fd, cnames, cerrs, n); + + /* if we got anything, fill in the blanks */ + if( got > 0 ){ + /* generate a Tcl object for each return argument */ + for(i=0; i<got; i++){ + if( cnames ){ + namesObjv[i] = Tcl_NewObj(); + Tcl_SetStringObj(namesObjv[i], cnames[i], + cnames[i] ? strlen(cnames[i]) : 0); + } + if( cerrs ){ + errsObjv[i] = Tcl_NewObj(); + Tcl_SetStringObj(errsObjv[i], cerrs[i], + cerrs[i] ? strlen(cerrs[i]) : 0); + } + } + /* make lists from the return arguments and set the return variables */ + if( cnames ){ + namesPtr = Tcl_NewObj(); + Tcl_SetListObj(namesPtr, got, namesObjv); + Tcl_ObjSetVar2(interp, objv[6], NULL, namesPtr, TCL_PARSE_PART1); + } + if( cerrs ){ + errsPtr = Tcl_NewObj(); + Tcl_SetListObj(errsPtr, got, errsObjv); + Tcl_ObjSetVar2(interp, objv[7], NULL, errsPtr, TCL_PARSE_PART1); + } + } + else{ + nullPtr = Tcl_NewObj(); + Tcl_SetStringObj(nullPtr, "", -1); + if( cnames ) + Tcl_ObjSetVar2(interp, objv[6], NULL, nullPtr, TCL_PARSE_PART1); + if( cerrs ) + Tcl_ObjSetVar2(interp, objv[7], NULL, nullPtr, TCL_PARSE_PART1); + } + + /* free up space */ + for(i=0; i<got; i++){ + if( cnames[i] ) xfree((char *)cnames[i]); + if( cerrs[i] ) xfree((char *)cerrs[i]); + } + if( cnames ) xfree((char *)cnames); + if( cerrs ) xfree((char *)cerrs); + if( namesObjv ) xfree((char *)namesObjv); + if( errsObjv ) xfree((char *)errsObjv); + + /* return the number of accesses as the tcl function result */ + Tcl_SetIntObj(resultPtr, got); + + /* return status */ + return(TCL_OK); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAInfo_Tcl + * + * Purpose: Tcl binding to XPAInfo procedure + * + * Tcl call: + * + * set got [xpainfo xpa template paramlist mode names errs n] + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPAInfo_Tcl(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +#else +static int XPAInfo_Tcl(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +#endif +{ + XPA xpa; + int got; + int n; + int i; + char *xpastr; + char *tmpl; + char *paramlist; + char *mode; + char *names; + char *errs; + char **cnames=NULL; + char **cerrs=NULL; + Tcl_Obj *resultPtr; + Tcl_Obj *nullPtr; + Tcl_Obj *namesPtr; + Tcl_Obj *errsPtr; + Tcl_Obj **namesObjv=NULL; + Tcl_Obj **errsObjv=NULL; + + /* make sure argument count is correct */ + if( objc != 8 ){ + Tcl_WrongNumArgs(interp, 1, objv, + "xpa template paramlist mode names errs n"); + return(TCL_ERROR); + } + + /* get result pointer */ + resultPtr = Tcl_GetObjResult(interp); + + /* get xpa struct pointer, which might be NULL */ + xpastr = Tcl_GetStringFromObj(objv[1], NULL); + if( TCL_NULLSTR(xpastr) ) + xpa = NULL; + else{ + /* get xpa, which is always arg 1 */ + if( Tcl_GetXPAFromObj(interp, objv[1], TY_CLIENT, &xpa) != TCL_OK){ + Tcl_SetStringObj(resultPtr, "XPA$ERROR: invalid xpa client handle", -1); + return(TCL_ERROR); + } + } + + /* get other args */ + tmpl = Tcl_GetStringFromObj(objv[2], NULL); + paramlist = Tcl_GetStringFromObj(objv[3], NULL); + mode = Tcl_GetStringFromObj(objv[4], NULL); + names = Tcl_GetStringFromObj(objv[5], NULL); + errs = Tcl_GetStringFromObj(objv[6], NULL); + if( (Tcl_GetIntFromObj(interp, objv[7], &n) != TCL_OK) || (n < 1) ){ + n = 1; + } + + /* allocate return buffers */ + if( !TCL_NULLSTR(names) ){ + cnames = (char **)xcalloc(n, sizeof(char *)); + namesObjv = (Tcl_Obj **)xcalloc(n, sizeof(Tcl_Obj *)); + } + if( !TCL_NULLSTR(errs) ){ + cerrs = (char **)xcalloc(n, sizeof(char *)); + errsObjv = (Tcl_Obj **)xcalloc(n, sizeof(Tcl_Obj *)); + } + + /* reset before we make C call */ + Tcl_ResetResult(interp); + + /* make the XPA C call */ + got = XPAInfo(xpa, tmpl, paramlist, mode, cnames, cerrs, n); + + /* if we got anything, fill in the blanks */ + if( got > 0 ){ + /* generate a Tcl object for each return argument */ + for(i=0; i<got; i++){ + if( cnames ){ + namesObjv[i] = Tcl_NewObj(); + Tcl_SetStringObj(namesObjv[i], cnames[i], + cnames[i] ? strlen(cnames[i]) : 0); + } + if( cerrs ){ + errsObjv[i] = Tcl_NewObj(); + Tcl_SetStringObj(errsObjv[i], cerrs[i], + cerrs[i] ? strlen(cerrs[i]) : 0); + } + } + /* make lists from the return arguments and set the return variables */ + if( cnames ){ + namesPtr = Tcl_NewObj(); + Tcl_SetListObj(namesPtr, got, namesObjv); + Tcl_ObjSetVar2(interp, objv[5], NULL, namesPtr, TCL_PARSE_PART1); + } + + if( cerrs ){ + errsPtr = Tcl_NewObj(); + Tcl_SetListObj(errsPtr, got, errsObjv); + Tcl_ObjSetVar2(interp, objv[6], NULL, errsPtr, TCL_PARSE_PART1); + } + } + else{ + nullPtr = Tcl_NewObj(); + Tcl_SetStringObj(nullPtr, "", -1); + if( cnames ) + Tcl_ObjSetVar2(interp, objv[5], NULL, nullPtr, TCL_PARSE_PART1); + if( cerrs ) + Tcl_ObjSetVar2(interp, objv[6], NULL, nullPtr, TCL_PARSE_PART1); + } + + /* free up space */ + for(i=0; i<got; i++){ + if( cnames[i] ) xfree((char *)cnames[i]); + if( cerrs[i] ) xfree((char *)cerrs[i]); + } + if( cnames ) xfree((char *)cnames); + if( cerrs ) xfree((char *)cerrs); + if( namesObjv ) xfree((char *)namesObjv); + if( errsObjv ) xfree((char *)errsObjv); + + /* return the number of accesses as the tcl function result */ + Tcl_SetIntObj(resultPtr, got); + + /* return status */ + return(TCL_OK); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAAccess_Tcl + * + * Purpose: Tcl binding to XPAAccess procedure + * + * Tcl call: + * + * set got [xpaaccess xpa template paramlist mode names errs n] + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPAAccess_Tcl(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +#else +static int XPAAccess_Tcl(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +#endif +{ + XPA xpa; + int got; + int n; + int i; + char *xpastr; + char *tmpl; + char *paramlist; + char *mode; + char *names; + char *errs; + char **cnames=NULL; + char **cerrs=NULL; + Tcl_Obj *resultPtr; + Tcl_Obj *nullPtr; + Tcl_Obj *namesPtr; + Tcl_Obj *errsPtr; + Tcl_Obj **namesObjv=NULL; + Tcl_Obj **errsObjv=NULL; + + /* make sure argument count is correct */ + if( objc != 8 ){ + Tcl_WrongNumArgs(interp, 1, objv, + "xpa template paramlist mode names errs n"); + return(TCL_ERROR); + } + + /* get result pointer */ + resultPtr = Tcl_GetObjResult(interp); + + /* get xpa struct pointer, which might be NULL */ + xpastr = Tcl_GetStringFromObj(objv[1], NULL); + if( TCL_NULLSTR(xpastr) ) + xpa = NULL; + else{ + /* get xpa, which is always arg 1 */ + if( Tcl_GetXPAFromObj(interp, objv[1], TY_CLIENT, &xpa) != TCL_OK){ + Tcl_SetStringObj(resultPtr, "XPA$ERROR: invalid xpa client handle", -1); + return(TCL_ERROR); + } + } + + /* get other args */ + tmpl = Tcl_GetStringFromObj(objv[2], NULL); + paramlist = Tcl_GetStringFromObj(objv[3], NULL); + mode = Tcl_GetStringFromObj(objv[4], NULL); + names = Tcl_GetStringFromObj(objv[5], NULL); + errs = Tcl_GetStringFromObj(objv[6], NULL); + if( (Tcl_GetIntFromObj(interp, objv[7], &n) != TCL_OK) || (n < 1) ){ + n = 1; + } + + if( !TCL_NULLSTR(names) ){ + cnames = (char **)xcalloc(n, sizeof(char *)); + namesObjv = (Tcl_Obj **)xcalloc(n, sizeof(Tcl_Obj *)); + } + if( !TCL_NULLSTR(errs) ){ + cerrs = (char **)xcalloc(n, sizeof(char *)); + errsObjv = (Tcl_Obj **)xcalloc(n, sizeof(Tcl_Obj *)); + } + + /* reset before we make C call */ + Tcl_ResetResult(interp); + + /* make the XPA C call */ + got = XPAAccess(xpa, tmpl, paramlist, mode, cnames, cerrs, n); + + /* if we got anything, fill in the blanks */ + if( got > 0 ){ + /* generate a Tcl object for each return argument */ + for(i=0; i<got; i++){ + if( cnames ){ + namesObjv[i] = Tcl_NewObj(); + Tcl_SetStringObj(namesObjv[i], cnames[i], + cnames[i] ? strlen(cnames[i]) : 0); + } + if( cerrs ){ + errsObjv[i] = Tcl_NewObj(); + Tcl_SetStringObj(errsObjv[i], cerrs[i], + cerrs[i] ? strlen(cerrs[i]) : 0); + } + } + /* make lists from the return arguments and set the return variables */ + if( cnames ){ + namesPtr = Tcl_NewObj(); + Tcl_SetListObj(namesPtr, got, namesObjv); + Tcl_ObjSetVar2(interp, objv[5], NULL, namesPtr, TCL_PARSE_PART1); + } + if( cerrs ){ + errsPtr = Tcl_NewObj(); + Tcl_SetListObj(errsPtr, got, errsObjv); + Tcl_ObjSetVar2(interp, objv[6], NULL, errsPtr, TCL_PARSE_PART1); + } + } + else{ + nullPtr = Tcl_NewObj(); + Tcl_SetStringObj(nullPtr, "", -1); + if( cnames ) + Tcl_ObjSetVar2(interp, objv[5], NULL, nullPtr, TCL_PARSE_PART1); + if( cerrs ) + Tcl_ObjSetVar2(interp, objv[6], NULL, nullPtr, TCL_PARSE_PART1); + } + + /* free up space */ + for(i=0; i<got; i++){ + if( cnames[i] ) xfree((char *)cnames[i]); + if( cerrs[i] ) xfree((char *)cerrs[i]); + } + if( cnames ) xfree((char *)cnames); + if( cerrs ) xfree((char *)cerrs); + if( namesObjv ) xfree((char *)namesObjv); + if( errsObjv ) xfree((char *)errsObjv); + + /* return the number of accesses as the tcl function result */ + Tcl_SetIntObj(resultPtr, got); + + /* return status */ + return(TCL_OK); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPANSLookup_Tcl + * + * Purpose: Tcl binding to XPANSLookup procedure + * + * Tcl call: + * + * set got [xpanslookup template type] + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPANSLookup_Tcl(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +#else +static int XPANSLookup_Tcl(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +#endif +{ + XPA xpa; + int i; + int got; + char *xpastr; + char *tmpl; + char *ttype; + char **xclasses; + char **names; + char **methods; + char **infos; + Tcl_Obj *resultPtr; + Tcl_Obj *nullPtr; + Tcl_Obj *classesPtr; + Tcl_Obj *namesPtr; + Tcl_Obj *methodsPtr; + Tcl_Obj *infosPtr; + Tcl_Obj **classesObjv; + Tcl_Obj **namesObjv; + Tcl_Obj **methodsObjv; + Tcl_Obj **infosObjv; + + /* make sure argument count is correct */ + if( objc != 7 ){ + Tcl_WrongNumArgs(interp, 1, objv, + "template type classes names methods infos"); + return(TCL_ERROR); + } + + /* get result pointer */ + resultPtr = Tcl_GetObjResult(interp); + + /* get other args */ + tmpl = Tcl_GetStringFromObj(objv[1], NULL); + ttype = Tcl_GetStringFromObj(objv[2], NULL); + + /* reset before we make C call */ + Tcl_ResetResult(interp); + + /* get xpa struct pointer, which might be NULL */ + xpastr = Tcl_GetStringFromObj(objv[1], NULL); + if( TCL_NULLSTR(xpastr) ) + xpa = NULL; + else{ + /* get xpa, which is always arg 1 */ + if( Tcl_GetXPAFromObj(interp, objv[1], TY_CLIENT, &xpa) != TCL_OK){ + Tcl_SetStringObj(resultPtr, "XPA$ERROR: invalid xpa client handle", -1); + return(TCL_ERROR); + } + } + + /* make the XPA C call */ + got = XPANSLookup(xpa, tmpl, ttype, &xclasses, &names, &methods, &infos); + + /* if we got anything, fill in the blanks */ + if( got > 0 ){ + /* allocate just enough pointers */ + classesObjv = (Tcl_Obj **)xcalloc(got, sizeof(Tcl_Obj *)); + namesObjv = (Tcl_Obj **)xcalloc(got, sizeof(Tcl_Obj *)); + methodsObjv = (Tcl_Obj **)xcalloc(got, sizeof(Tcl_Obj *)); + infosObjv = (Tcl_Obj **)xcalloc(got, sizeof(Tcl_Obj *)); + + /* generate a Tcl object for each return argument */ + for(i=0; i<got; i++){ + classesObjv[i] = Tcl_NewObj(); + Tcl_SetStringObj(classesObjv[i], xclasses[i], strlen(xclasses[i])); + namesObjv[i] = Tcl_NewObj(); + Tcl_SetStringObj(namesObjv[i], names[i], strlen(names[i])); + methodsObjv[i] = Tcl_NewObj(); + Tcl_SetStringObj(methodsObjv[i], methods[i], strlen(methods[i])); + infosObjv[i] = Tcl_NewObj(); + Tcl_SetStringObj(infosObjv[i], infos[i], strlen(infos[i])); + } + /* make lists from the return arguments and set the return variables */ + classesPtr = Tcl_NewObj(); + Tcl_SetListObj(classesPtr, got, classesObjv); + Tcl_ObjSetVar2(interp, objv[3], NULL, classesPtr, TCL_PARSE_PART1); + + namesPtr = Tcl_NewObj(); + Tcl_SetListObj(namesPtr, got, namesObjv); + Tcl_ObjSetVar2(interp, objv[4], NULL, namesPtr, TCL_PARSE_PART1); + + methodsPtr = Tcl_NewObj(); + Tcl_SetListObj(methodsPtr, got, methodsObjv); + Tcl_ObjSetVar2(interp, objv[5], NULL, methodsPtr, TCL_PARSE_PART1); + + infosPtr = Tcl_NewObj(); + Tcl_SetListObj(infosPtr, got, infosObjv); + Tcl_ObjSetVar2(interp, objv[5], NULL, infosPtr, TCL_PARSE_PART1); + + /* free up the space */ + for(i=0; i<got; i++){ + /* done with these strings */ + xfree(xclasses[i]); + xfree(names[i]); + xfree(methods[i]); + xfree(infos[i]); + } + /* free up arrays alloc'ed by name server */ + if( got > 0 ){ + xfree(xclasses); + xfree(names); + xfree(methods); + xfree(infos); + xfree(classesObjv); + xfree(namesObjv); + xfree(methodsObjv); + xfree(infosObjv); + } + } + else{ + nullPtr = Tcl_NewObj(); + Tcl_SetStringObj(nullPtr, "", -1); + Tcl_ObjSetVar2(interp, objv[3], NULL, nullPtr, TCL_PARSE_PART1); + Tcl_ObjSetVar2(interp, objv[4], NULL, nullPtr, TCL_PARSE_PART1); + Tcl_ObjSetVar2(interp, objv[5], NULL, nullPtr, TCL_PARSE_PART1); + Tcl_ObjSetVar2(interp, objv[6], NULL, nullPtr, TCL_PARSE_PART1); + } + + /* return the number of accesses as the tcl function result */ + Tcl_SetIntObj(resultPtr, got); + + /* return status */ + return(TCL_OK); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPANSKeepAlive_Tcl + * + * Purpose: Tcl binding to XPANSKeepAlive procedure + * + * Tcl call: + * + * xpafree xpa + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPANSKeepAlive_Tcl(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +#else +static int XPANSKeepAlive_Tcl(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +#endif +{ + XPA xpa; + int type=0; + char *s=NULL; + + /* make sure argument count is correct */ + if( objc < 2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "xpa [type]"); + return(TCL_ERROR); + } + + /* get xpa, which is always arg 1 */ + if( Tcl_GetXPAFromObj(interp, objv[1], TY_SERVER, &xpa) != TCL_OK){ + return(TCL_ERROR); + } + + /* optional type, usually not specified for default */ + if( (objc >= 3) && (s = Tcl_GetStringFromObj(objv[2], NULL)) != NULL ) + type = atoi(s); + + /* reset error/result condition */ + Tcl_ResetResult(interp); + + /* call the XPANSKeepAlive routine */ + XPANSKeepAlive(xpa, type); + + return(TCL_OK); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPARemote_Tcl + * + * Purpose: Tcl binding to XPARemote procedure + * + * Tcl call: + * + * xpaRemote xpa host acl + * + * use the empty string to specify NULL arguments + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPARemote_Tcl(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +#else +static int XPARemote_Tcl(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +#endif +{ + int got; + char *host; + char *acl="+"; + char *s; + char *mode=NULL; + char tbuf[SZ_LINE]; + XPA xpa; + Tcl_Obj *resultPtr; + + /* make sure argument count is correct */ + if( (objc < 3) || (objc > 5) ){ + Tcl_WrongNumArgs(interp, 1, objv, "xpa host [acl] [-proxy]"); + return(TCL_ERROR); + } + + /* get result pointer */ + resultPtr = Tcl_GetObjResult(interp); + + /* get xpa, which is always arg 1 */ + if( Tcl_GetXPAFromObj(interp, objv[1], TY_SERVER, &xpa) != TCL_OK){ + return(TCL_ERROR); + } + + /* make sure we are using inet sockets */ + if( XPAMtype() != XPA_INET ){ + snprintf(tbuf, SZ_LINE, "remote requires that XPA_METHOD be 'inet'\n"); + Tcl_SetStringObj(resultPtr, tbuf, -1); + return(TCL_ERROR); + } + + /* get required host */ + host = Tcl_GetStringFromObj(objv[2], NULL); + + /* get optional acl */ + if( objc >= 4 ){ + s = Tcl_GetStringFromObj(objv[3], NULL); + if( !strcmp(s, "-proxy") ){ + mode="proxy=true"; + } + else{ + acl = s; + } + } + + /* get optional -proxy switch */ + if( objc == 5 ){ + s = Tcl_GetStringFromObj(objv[4], NULL); + if( !strcmp(s, "-proxy") ){ + mode="proxy=true"; + } + else if( mode ){ + acl = s; + } + else{ + snprintf(tbuf, SZ_LINE, + "XPA$ERROR: invalid arg (%s): xpa -remote host [acl] [-proxy]\n", + s); + Tcl_SetStringObj(resultPtr, tbuf, -1); + return(TCL_ERROR); + } + } + + /* reset error/result condition */ + Tcl_ResetResult(interp); + + /* set up the tcl handler for the xpa access point */ + got = XPARemote(xpa, host, acl, mode); + if( got >= 0 ){ + return(TCL_OK); + } + else{ + snprintf(tbuf, SZ_LINE, + "XPA$ERROR: remote xpans %s failed to process %s\n", + host, xpa->name); + Tcl_SetStringObj(resultPtr, tbuf, -1); + return(TCL_ERROR); + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAError_Tcl + * + * Purpose: Tcl binding to XPAError procedure + * + * Tcl call: + * + * xpaerror xpa errmess + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPAError_Tcl(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +#else +static int XPAError_Tcl(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +#endif +{ + char *message; + XPA xpa; + + /* make sure argument count is correct */ + if( objc != 3 ){ + Tcl_WrongNumArgs(interp, 1, objv, "xpa message"); + return(TCL_ERROR); + } + + /* get xpa, which is always arg 1 */ + if( Tcl_GetXPAFromObj(interp, objv[1], TY_SERVER, &xpa) != TCL_OK){ + return(TCL_ERROR); + } + + /* get message string */ + message = Tcl_GetStringFromObj(objv[2], NULL); + + /* reset error/result condition */ + Tcl_ResetResult(interp); + + /* call the XPAError routine */ + XPAError(xpa, message); + + /* no error message (too lazy) */ + return(TCL_OK); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAMessage_Tcl + * + * Purpose: Tcl binding to XPAMessage procedure + * + * Tcl call: + * + * xpamessage xpa errmess + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPAMessage_Tcl(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +#else +static int XPAMessage_Tcl(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +#endif +{ + char *message; + XPA xpa; + + /* make sure argument count is correct */ + if( objc != 3 ){ + Tcl_WrongNumArgs(interp, 1, objv, "xpa message"); + return(TCL_ERROR); + } + + /* get xpa, which is always arg 1 */ + if( Tcl_GetXPAFromObj(interp, objv[1], TY_SERVER, &xpa) != TCL_OK){ + return(TCL_ERROR); + } + + /* get message string */ + message = Tcl_GetStringFromObj(objv[2], NULL); + + /* reset error/result condition */ + Tcl_ResetResult(interp); + + /* call the XPAMessage routine */ + XPAMessage(xpa, message); + + /* no error message (too lazy) */ + return(TCL_OK); +} + +/* + *---------------------------------------------------------------------------- + * + * + * Public Routines and Data + * + * + *---------------------------------------------------------------------------- + */ + +/* + *---------------------------------------------------------------------------- + * + * Routine: Xpa_Init + * + * Purpose: initialize Tcl xpa package + * + * Returns: tcl return code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +Tclxpa_Init (void *vinterp) +#else +int Tclxpa_Init (vinterp) + void *vinterp; +#endif +{ + Tcl_Interp *interp = (Tcl_Interp *)vinterp; + + if( +#ifdef USE_TCL_STUBS + Tcl_InitStubs(interp, "8.4", 0) +#else + Tcl_PkgRequire(interp, "Tcl", "8.4", 0) +#endif + == NULL) { + return TCL_ERROR; + } + + /* add xpa commands to this interpreter */ + Tcl_CreateObjCommand(interp, "xpanew", XPANew_Tcl, + (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); + + Tcl_CreateObjCommand(interp, "xpafree", XPAFree_Tcl, + (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); + + Tcl_CreateObjCommand(interp, "xpainfonew", XPAInfoNew_Tcl, + (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); + + Tcl_CreateObjCommand(interp, "xpacmdnew", XPACmdNew_Tcl, + (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); + + Tcl_CreateObjCommand(interp, "xpacmddel", XPACmdDel_Tcl, + (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); + + Tcl_CreateObjCommand(interp, "xpacmdadd", XPACmdAdd_Tcl, + (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); + + Tcl_CreateObjCommand(interp, "xparec", XPARec_Tcl, + (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); + + Tcl_CreateObjCommand(interp, "xpasetbuf", XPASetBuf_Tcl, + (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); + + Tcl_CreateObjCommand(interp, "xpaopen", XPAOpen_Tcl, + (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); + + Tcl_CreateObjCommand(interp, "xpaclose", XPAClose_Tcl, + (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); + + Tcl_CreateObjCommand(interp, "xpaget", XPAGet_Tcl, + (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); + + Tcl_CreateObjCommand(interp, "xpagetfd", XPAGetFd_Tcl, + (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); + + Tcl_CreateObjCommand(interp, "xpaset", XPASet_Tcl, + (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); + + Tcl_CreateObjCommand(interp, "xpasetfd", XPASetFd_Tcl, + (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); + + Tcl_CreateObjCommand(interp, "xpainfo", XPAInfo_Tcl, + (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); + + Tcl_CreateObjCommand(interp, "xpaaccess", XPAAccess_Tcl, + (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); + + Tcl_CreateObjCommand(interp, "xpanslookup", XPANSLookup_Tcl, + (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); + + Tcl_CreateObjCommand(interp, "xpanskeepalive", XPANSKeepAlive_Tcl, + (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); + + Tcl_CreateObjCommand(interp, "xparemote", XPARemote_Tcl, + (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); + + Tcl_CreateObjCommand(interp, "xpaerror", XPAError_Tcl, + (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); + + Tcl_CreateObjCommand(interp, "xpamessage", XPAMessage_Tcl, + (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); + + Tcl_PkgProvide(interp, "tclxpa", "2.1"); + return(TCL_OK); +} + +/* required for tclkit 8.6 */ +int Tclxpa_Unload() { return TCL_ERROR; } +int Tclxpa_SafeUnload() { return TCL_ERROR; } +int Tclxpa_SafeInit() { return TCL_ERROR; } + + +int xpa_tclbinding = 1; + +#else + +int xpa_tclbinding = 0; + +#endif |