/* * t4stored.cpp -- * * This file implements a mechanism for defining stored procedures * from vertices containing strings. * * Authors: Jacob Levy and Jean-Claude Wippler. * jyl@best.com jcw@equi4.com * * Copyright (c) 2000-2003, JYL Software Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE, EVEN IF * JYL SOFTWARE INC. IS MADE AWARE OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "t4graphrep.h" /* * T4Graph_DefineStoredProcedure -- * * Define a new Tcl command named "cmdname" based on the string * value of "v". * * Results: * If successful, returns a T4CmdInfo * for the newly defined command. * * Side effects: * May define a new Tcl procedure. */ T4CmdInfo * T4Graph_DefineStoredProcedure(Tcl_Interp *interp, char *cmdname, T4Storage *s, e4_Vertex v) { const char *storedproc; Tcl_Obj *obj; int objc; Tcl_Obj **objv; char *buf, *argstr, *bodystr; Tcl_CmdInfo ci; T4CmdInfo *cmdInfo; /* * Vertex must have string value. */ if (!v.Get(storedproc) || (storedproc == NULL)) { Tcl_AppendResult(interp, cmdname, ": cannot define", NULL); return NULL; } /* * Parse the stored procedure into args and body: */ obj = Tcl_NewStringObj(storedproc, strlen(storedproc)); if (Tcl_ListObjGetElements(interp, obj, &objc, &objv) == TCL_ERROR) { return NULL; } if (objc != 2) { Tcl_AppendResult(interp, cmdname, ": malformed stored procedure", NULL); return NULL; } argstr = Tcl_GetString(objv[0]); bodystr = Tcl_GetString(objv[1]); /* * Modify the args to pass "this" as first argument. When called, the * first argument will be set to Tcl_Obj for the containing node. */ buf = Tcl_Alloc(6 + strlen(argstr)); sprintf(buf, "this %s", argstr); argstr = buf; /* * Now prepare a new command to create a proc. Then invoke it with * Tcl_Eval. */ buf = Tcl_Alloc(4 + 1 + strlen(cmdname) + 1 + 2 + strlen(argstr) + 1 + 2 + strlen(bodystr) + 1); sprintf(buf, "proc %s {%s} {%s}", cmdname, argstr, bodystr); if (Tcl_Eval(interp, buf) == TCL_ERROR) { return NULL; } Tcl_Free(buf); Tcl_Free(argstr); Tcl_DecrRefCount(obj); /* * Prepare a T4CmdInfo for the new command. */ if (Tcl_GetCommandInfo(interp, cmdname, &ci) == 0) { return NULL; } cmdInfo = (T4CmdInfo *) Tcl_Alloc(sizeof(T4CmdInfo)); cmdInfo->cmdName = cmdname; cmdInfo->objProc = ci.objProc; cmdInfo->objClientData = ci.objClientData; /* * Associate the cmdInfo with this vertex. */ s->SetVertexStoredCmdInfo(interp, v, cmdInfo); Tcl_ResetResult(interp); return cmdInfo; }