2 * tclTestProcBodyObj.c --
4 * Implements the "procbodytest" package, which contains commands to test
5 * creation of Tcl procedures whose body argument is a Tcl_Obj of type
6 * "procbody" rather than a string.
8 * Copyright (c) 1998 by Scriptics Corporation.
10 * See the file "license.terms" for information on usage and redistribution of
11 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
15 # define USE_TCL_STUBS
20 * name and version of this package
23 static const char packageName[] = "procbodytest";
24 static const char packageVersion[] = "1.1";
27 * Name of the commands exported by this package
30 static const char procCommand[] = "proc";
31 static const char checkCommand[] = "check";
34 * this struct describes an entry in the table of command names and command
38 typedef struct CmdTable {
39 const char *cmdName; /* command name */
40 Tcl_ObjCmdProc *proc; /* command proc */
41 int exportIt; /* if 1, export the command */
45 * Declarations for functions defined in this file.
48 static int ProcBodyTestProcObjCmd(ClientData dummy,
49 Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]);
50 static int ProcBodyTestCheckObjCmd(ClientData dummy,
51 Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]);
52 static int ProcBodyTestInitInternal(Tcl_Interp *interp, int isSafe);
53 static int RegisterCommand(Tcl_Interp* interp,
54 const char *namespace, const CmdTable *cmdTablePtr);
57 * List of commands to create when the package is loaded; must go after the
58 * declarations of the enable command procedure.
61 static const CmdTable commands[] = {
62 { procCommand, ProcBodyTestProcObjCmd, 1 },
63 { checkCommand, ProcBodyTestCheckObjCmd, 1 },
67 static const CmdTable safeCommands[] = {
68 { procCommand, ProcBodyTestProcObjCmd, 1 },
69 { checkCommand, ProcBodyTestCheckObjCmd, 1 },
74 *----------------------------------------------------------------------
76 * Procbodytest_Init --
78 * This function initializes the "procbodytest" package.
81 * A standard Tcl result.
86 *----------------------------------------------------------------------
91 Tcl_Interp *interp) /* the Tcl interpreter for which the package
94 return ProcBodyTestInitInternal(interp, 0);
98 *----------------------------------------------------------------------
100 * Procbodytest_SafeInit --
102 * This function initializes the "procbodytest" package.
105 * A standard Tcl result.
110 *----------------------------------------------------------------------
114 Procbodytest_SafeInit(
115 Tcl_Interp *interp) /* the Tcl interpreter for which the package
118 return ProcBodyTestInitInternal(interp, 1);
122 *----------------------------------------------------------------------
126 * This function registers a command in the context of the given
130 * A standard Tcl result.
135 *----------------------------------------------------------------------
140 Tcl_Interp* interp, /* the Tcl interpreter for which the operation
142 const char *namespace, /* the namespace in which the command is
144 const CmdTable *cmdTablePtr)/* the command to register */
148 if (cmdTablePtr->exportIt) {
149 sprintf(buf, "namespace eval %s { namespace export %s }",
150 namespace, cmdTablePtr->cmdName);
151 if (Tcl_EvalEx(interp, buf, -1, 0) != TCL_OK) {
156 sprintf(buf, "%s::%s", namespace, cmdTablePtr->cmdName);
157 Tcl_CreateObjCommand(interp, buf, cmdTablePtr->proc, 0, 0);
162 *----------------------------------------------------------------------
164 * ProcBodyTestInitInternal --
166 * This function initializes the Loader package.
167 * The isSafe flag is 1 if the interpreter is safe, 0 otherwise.
170 * A standard Tcl result.
175 *----------------------------------------------------------------------
179 ProcBodyTestInitInternal(
180 Tcl_Interp *interp, /* the Tcl interpreter for which the package
182 int isSafe) /* 1 if this is a safe interpreter */
184 const CmdTable *cmdTablePtr;
186 cmdTablePtr = (isSafe) ? &safeCommands[0] : &commands[0];
187 for ( ; cmdTablePtr->cmdName ; cmdTablePtr++) {
188 if (RegisterCommand(interp, packageName, cmdTablePtr) != TCL_OK) {
193 return Tcl_PkgProvide(interp, packageName, packageVersion);
197 *----------------------------------------------------------------------
199 * ProcBodyTestProcObjCmd --
201 * Implements the "procbodytest::proc" command. Here is the command
203 * procbodytest::proc newName argList bodyName
204 * Looks up a procedure called $bodyName and, if the procedure exists,
205 * constructs a Tcl_Obj of type "procbody" and calls Tcl_ProcObjCmd.
207 * newName the name of the procedure to be created
208 * argList the argument list for the procedure
209 * bodyName the name of an existing procedure from which the
210 * body is to be copied.
211 * This command can be used to trigger the branches in Tcl_ProcObjCmd that
212 * construct a proc from a "procbody", for example:
213 * proc a {x} {return $x}
215 * procbodytest::proc b {x} a
216 * Note the call to "a 123", which is necessary so that the Proc pointer
217 * for "a" is filled in by the internal compiler; this is a hack.
220 * Returns a standard Tcl code.
223 * A new procedure is created.
224 * Leaves an error message in the interp's result on error.
226 *----------------------------------------------------------------------
230 ProcBodyTestProcObjCmd(
231 ClientData dummy, /* context; not used */
232 Tcl_Interp *interp, /* the current interpreter */
233 int objc, /* argument count */
234 Tcl_Obj *const objv[]) /* arguments */
236 const char *fullName;
239 Proc *procPtr = NULL;
245 Tcl_WrongNumArgs(interp, 1, objv, "newName argsList bodyName");
250 * Find the Command pointer to this procedure
253 fullName = Tcl_GetString(objv[3]);
254 procCmd = Tcl_FindCommand(interp, fullName, NULL, TCL_LEAVE_ERR_MSG);
255 if (procCmd == NULL) {
259 cmdPtr = (Command *) procCmd;
262 * check that this is a procedure and not a builtin command:
263 * If a procedure, cmdPtr->objClientData is TclIsProc(cmdPtr).
266 if (cmdPtr->objClientData != TclIsProc(cmdPtr)) {
267 Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
268 "command \"", fullName, "\" is not a Tcl procedure", NULL);
273 * it is a Tcl procedure: the client data is the Proc structure
276 procPtr = (Proc *) cmdPtr->objClientData;
277 if (procPtr == NULL) {
278 Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "procedure \"",
279 fullName, "\" does not have a Proc struct!", NULL);
284 * create a new object, initialize our argument vector, call into Tcl
287 bodyObjPtr = TclNewProcBodyObj(procPtr);
288 if (bodyObjPtr == NULL) {
289 Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
290 "failed to create a procbody object for procedure \"",
291 fullName, "\"", NULL);
294 Tcl_IncrRefCount(bodyObjPtr);
299 myobjv[3] = bodyObjPtr;
302 result = Tcl_ProcObjCmd(NULL, interp, objc, myobjv);
303 Tcl_DecrRefCount(bodyObjPtr);
309 *----------------------------------------------------------------------
311 * ProcBodyTestCheckObjCmd --
313 * Implements the "procbodytest::check" command. Here is the command
315 * procbodytest::check
317 * Performs an internal check that the Tcl_PkgPresent() command returns
318 * the same version number as was registered when the procbodytest package
319 * was provided. Places a boolean in the interp result indicating the
323 * Returns a standard Tcl code.
325 *----------------------------------------------------------------------
329 ProcBodyTestCheckObjCmd(
330 ClientData dummy, /* context; not used */
331 Tcl_Interp *interp, /* the current interpreter */
332 int objc, /* argument count */
333 Tcl_Obj *const objv[]) /* arguments */
338 Tcl_WrongNumArgs(interp, 1, objv, "");
342 version = Tcl_PkgPresent(interp, packageName, packageVersion, 1);
343 Tcl_SetObjResult(interp, Tcl_NewBooleanObj(
344 strcmp(version, packageVersion) == 0));