tclTest.c

Go to the documentation of this file.
00001 /*
00002  * tclTest.c --
00003  *
00004  *      This file contains C command functions for a bunch of additional Tcl
00005  *      commands that are used for testing out Tcl's C interfaces. These
00006  *      commands are not normally included in Tcl applications; they're only
00007  *      used for testing.
00008  *
00009  * Copyright (c) 1993-1994 The Regents of the University of California.
00010  * Copyright (c) 1994-1997 Sun Microsystems, Inc.
00011  * Copyright (c) 1998-2000 Ajuba Solutions.
00012  * Copyright (c) 2003 by Kevin B. Kenny.  All rights reserved.
00013  *
00014  * See the file "license.terms" for information on usage and redistribution of
00015  * this file, and for a DISCLAIMER OF ALL WARRANTIES.
00016  *
00017  * RCS: @(#) $Id: tclTest.c,v 1.113 2007/12/13 15:23:20 dgp Exp $
00018  */
00019 
00020 #define TCL_TEST
00021 #include "tclInt.h"
00022 
00023 /*
00024  * Required for Testregexp*Cmd
00025  */
00026 #include "tclRegexp.h"
00027 
00028 /*
00029  * Required for TestlocaleCmd
00030  */
00031 #include <locale.h>
00032 
00033 /*
00034  * Required for the TestChannelCmd and TestChannelEventCmd
00035  */
00036 #include "tclIO.h"
00037 
00038 /*
00039  * Declare external functions used in Windows tests.
00040  */
00041 
00042 /*
00043  * Dynamic string shared by TestdcallCmd and DelCallbackProc; used to collect
00044  * the results of the various deletion callbacks.
00045  */
00046 
00047 static Tcl_DString delString;
00048 static Tcl_Interp *delInterp;
00049 
00050 /*
00051  * One of the following structures exists for each asynchronous handler
00052  * created by the "testasync" command".
00053  */
00054 
00055 typedef struct TestAsyncHandler {
00056     int id;                     /* Identifier for this handler. */
00057     Tcl_AsyncHandler handler;   /* Tcl's token for the handler. */
00058     char *command;              /* Command to invoke when the handler is
00059                                  * invoked. */
00060     struct TestAsyncHandler *nextPtr;
00061                                 /* Next is list of handlers. */
00062 } TestAsyncHandler;
00063 
00064 static TestAsyncHandler *firstHandler = NULL;
00065 
00066 /*
00067  * The dynamic string below is used by the "testdstring" command to test the
00068  * dynamic string facilities.
00069  */
00070 
00071 static Tcl_DString dstring;
00072 
00073 /*
00074  * The command trace below is used by the "testcmdtraceCmd" command to test
00075  * the command tracing facilities.
00076  */
00077 
00078 static Tcl_Trace cmdTrace;
00079 
00080 /*
00081  * One of the following structures exists for each command created by
00082  * TestdelCmd:
00083  */
00084 
00085 typedef struct DelCmd {
00086     Tcl_Interp *interp;         /* Interpreter in which command exists. */
00087     char *deleteCmd;            /* Script to execute when command is deleted.
00088                                  * Malloc'ed. */
00089 } DelCmd;
00090 
00091 /*
00092  * The following is used to keep track of an encoding that invokes a Tcl
00093  * command.
00094  */
00095 
00096 typedef struct TclEncoding {
00097     Tcl_Interp *interp;
00098     char *toUtfCmd;
00099     char *fromUtfCmd;
00100 } TclEncoding;
00101 
00102 /*
00103  * The counter below is used to determine if the TestsaveresultFree routine
00104  * was called for a result.
00105  */
00106 
00107 static int freeCount;
00108 
00109 /*
00110  * Boolean flag used by the "testsetmainloop" and "testexitmainloop" commands.
00111  */
00112 
00113 static int exitMainLoop = 0;
00114 
00115 /*
00116  * Event structure used in testing the event queue management procedures.
00117  */
00118 
00119 typedef struct TestEvent {
00120     Tcl_Event header;           /* Header common to all events */
00121     Tcl_Interp *interp;         /* Interpreter that will handle the event */
00122     Tcl_Obj *command;           /* Command to evaluate when the event occurs */
00123     Tcl_Obj *tag;               /* Tag for this event used to delete it */
00124 } TestEvent;
00125 
00126 /*
00127  * Simple detach/attach facility for testchannel cut|splice. Allow testing of
00128  * channel transfer in core testsuite.
00129  */
00130 
00131 typedef struct TestChannel {
00132     Tcl_Channel chan;           /* Detached channel */
00133     struct TestChannel *nextPtr;/* Next in detached channel pool */
00134 } TestChannel;
00135 
00136 static TestChannel *firstDetached;
00137 
00138 /*
00139  * Forward declarations for procedures defined later in this file:
00140  */
00141 
00142 int                     Tcltest_Init(Tcl_Interp *interp);
00143 static int              AsyncHandlerProc(ClientData clientData,
00144                             Tcl_Interp *interp, int code);
00145 #ifdef TCL_THREADS
00146 static Tcl_ThreadCreateType AsyncThreadProc(ClientData);
00147 #endif
00148 static void             CleanupTestSetassocdataTests(
00149                             ClientData clientData, Tcl_Interp *interp);
00150 static void             CmdDelProc1(ClientData clientData);
00151 static void             CmdDelProc2(ClientData clientData);
00152 static int              CmdProc1(ClientData clientData,
00153                             Tcl_Interp *interp, int argc, const char **argv);
00154 static int              CmdProc2(ClientData clientData,
00155                             Tcl_Interp *interp, int argc, const char **argv);
00156 static void             CmdTraceDeleteProc(
00157                             ClientData clientData, Tcl_Interp *interp,
00158                             int level, char *command, Tcl_CmdProc *cmdProc,
00159                             ClientData cmdClientData, int argc,
00160                             char **argv);
00161 static void             CmdTraceProc(ClientData clientData,
00162                             Tcl_Interp *interp, int level, char *command,
00163                             Tcl_CmdProc *cmdProc, ClientData cmdClientData,
00164                             int argc, char **argv);
00165 static int              CreatedCommandProc(
00166                             ClientData clientData, Tcl_Interp *interp,
00167                             int argc, const char **argv);
00168 static int              CreatedCommandProc2(
00169                             ClientData clientData, Tcl_Interp *interp,
00170                             int argc, const char **argv);
00171 static void             DelCallbackProc(ClientData clientData,
00172                             Tcl_Interp *interp);
00173 static int              DelCmdProc(ClientData clientData,
00174                             Tcl_Interp *interp, int argc, const char **argv);
00175 static void             DelDeleteProc(ClientData clientData);
00176 static void             EncodingFreeProc(ClientData clientData);
00177 static int              EncodingToUtfProc(ClientData clientData,
00178                             const char *src, int srcLen, int flags,
00179                             Tcl_EncodingState *statePtr, char *dst,
00180                             int dstLen, int *srcReadPtr, int *dstWrotePtr,
00181                             int *dstCharsPtr);
00182 static int              EncodingFromUtfProc(ClientData clientData,
00183                             const char *src, int srcLen, int flags,
00184                             Tcl_EncodingState *statePtr, char *dst,
00185                             int dstLen, int *srcReadPtr, int *dstWrotePtr,
00186                             int *dstCharsPtr);
00187 static void             ExitProcEven(ClientData clientData);
00188 static void             ExitProcOdd(ClientData clientData);
00189 static int              GetTimesCmd(ClientData clientData,
00190                             Tcl_Interp *interp, int argc, const char **argv);
00191 static void             MainLoop(void);
00192 static int              NoopCmd(ClientData clientData,
00193                             Tcl_Interp *interp, int argc, const char **argv);
00194 static int              NoopObjCmd(ClientData clientData,
00195                             Tcl_Interp *interp, int objc,
00196                             Tcl_Obj *const objv[]);
00197 static int              ObjTraceProc(ClientData clientData,
00198                             Tcl_Interp *interp, int level, const char *command,
00199                             Tcl_Command commandToken, int objc,
00200                             Tcl_Obj *const objv[]);
00201 static void             ObjTraceDeleteProc(ClientData clientData);
00202 static void             PrintParse(Tcl_Interp *interp, Tcl_Parse *parsePtr);
00203 static void             SpecialFree(char *blockPtr);
00204 static int              StaticInitProc(Tcl_Interp *interp);
00205 #undef USE_OBSOLETE_FS_HOOKS
00206 #ifdef USE_OBSOLETE_FS_HOOKS
00207 static int              TestaccessprocCmd(ClientData dummy,
00208                             Tcl_Interp *interp, int argc, const char **argv);
00209 static int              TestopenfilechannelprocCmd(
00210                             ClientData dummy, Tcl_Interp *interp, int argc,
00211                             const char **argv);
00212 static int              TeststatprocCmd(ClientData dummy,
00213                             Tcl_Interp *interp, int argc, const char **argv);
00214 static int              PretendTclpAccess(const char *path, int mode);
00215 static int              TestAccessProc1(const char *path, int mode);
00216 static int              TestAccessProc2(const char *path, int mode);
00217 static int              TestAccessProc3(const char *path, int mode);
00218 static Tcl_Channel      PretendTclpOpenFileChannel(
00219                             Tcl_Interp *interp, const char *fileName,
00220                             const char *modeString, int permissions);
00221 static Tcl_Channel      TestOpenFileChannelProc1(
00222                             Tcl_Interp *interp, const char *fileName,
00223                             const char *modeString, int permissions);
00224 static Tcl_Channel      TestOpenFileChannelProc2(
00225                             Tcl_Interp *interp, const char *fileName,
00226                             const char *modeString, int permissions);
00227 static Tcl_Channel      TestOpenFileChannelProc3(
00228                             Tcl_Interp *interp, const char *fileName,
00229                             const char *modeString, int permissions);
00230 static int              PretendTclpStat(const char *path, struct stat *buf);
00231 static int              TestStatProc1(const char *path, struct stat *buf);
00232 static int              TestStatProc2(const char *path, struct stat *buf);
00233 static int              TestStatProc3(const char *path, struct stat *buf);
00234 #endif
00235 static int              TestasyncCmd(ClientData dummy,
00236                             Tcl_Interp *interp, int argc, const char **argv);
00237 static int              TestcmdinfoCmd(ClientData dummy,
00238                             Tcl_Interp *interp, int argc, const char **argv);
00239 static int              TestcmdtokenCmd(ClientData dummy,
00240                             Tcl_Interp *interp, int argc, const char **argv);
00241 static int              TestcmdtraceCmd(ClientData dummy,
00242                             Tcl_Interp *interp, int argc, const char **argv);
00243 static int              TestcreatecommandCmd(ClientData dummy,
00244                             Tcl_Interp *interp, int argc, const char **argv);
00245 static int              TestdcallCmd(ClientData dummy,
00246                             Tcl_Interp *interp, int argc, const char **argv);
00247 static int              TestdelCmd(ClientData dummy,
00248                             Tcl_Interp *interp, int argc, const char **argv);
00249 static int              TestdelassocdataCmd(ClientData dummy,
00250                             Tcl_Interp *interp, int argc, const char **argv);
00251 static int              TestdstringCmd(ClientData dummy,
00252                             Tcl_Interp *interp, int argc, const char **argv);
00253 static int              TestencodingObjCmd(ClientData dummy,
00254                             Tcl_Interp *interp, int objc,
00255                             Tcl_Obj *const objv[]);
00256 static int              TestevalexObjCmd(ClientData dummy,
00257                             Tcl_Interp *interp, int objc,
00258                             Tcl_Obj *const objv[]);
00259 static int              TestevalobjvObjCmd(ClientData dummy,
00260                             Tcl_Interp *interp, int objc,
00261                             Tcl_Obj *const objv[]);
00262 static int              TesteventObjCmd(ClientData unused,
00263                             Tcl_Interp *interp, int argc,
00264                             Tcl_Obj *const objv[]);
00265 static int              TesteventProc(Tcl_Event *event, int flags);
00266 static int              TesteventDeleteProc(Tcl_Event *event,
00267                             ClientData clientData);
00268 static int              TestexithandlerCmd(ClientData dummy,
00269                             Tcl_Interp *interp, int argc, const char **argv);
00270 static int              TestexprlongCmd(ClientData dummy,
00271                             Tcl_Interp *interp, int argc, const char **argv);
00272 static int              TestexprlongobjCmd(ClientData dummy,
00273                             Tcl_Interp *interp, int objc,
00274                             Tcl_Obj *const objv[]);
00275 static int              TestexprdoubleCmd(ClientData dummy,
00276                             Tcl_Interp *interp, int argc, const char **argv);
00277 static int              TestexprdoubleobjCmd(ClientData dummy,
00278                             Tcl_Interp *interp, int objc,
00279                             Tcl_Obj *const objv[]);
00280 static int              TestexprparserObjCmd(ClientData dummy,
00281                             Tcl_Interp *interp, int objc,
00282                             Tcl_Obj *const objv[]);
00283 static int              TestexprstringCmd(ClientData dummy,
00284                             Tcl_Interp *interp, int argc, const char **argv);
00285 static int              TestfileCmd(ClientData dummy,
00286                             Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]);
00287 static int              TestfilelinkCmd(ClientData dummy,
00288                             Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]);
00289 static int              TestfeventCmd(ClientData dummy,
00290                             Tcl_Interp *interp, int argc, const char **argv);
00291 static int              TestgetassocdataCmd(ClientData dummy,
00292                             Tcl_Interp *interp, int argc, const char **argv);
00293 static int              TestgetintCmd(ClientData dummy,
00294                             Tcl_Interp *interp, int argc, const char **argv);
00295 static int              TestgetplatformCmd(ClientData dummy,
00296                             Tcl_Interp *interp, int argc, const char **argv);
00297 static int              TestgetvarfullnameCmd(
00298                             ClientData dummy, Tcl_Interp *interp,
00299                             int objc, Tcl_Obj *const objv[]);
00300 static int              TestinterpdeleteCmd(ClientData dummy,
00301                             Tcl_Interp *interp, int argc, const char **argv);
00302 static int              TestlinkCmd(ClientData dummy,
00303                             Tcl_Interp *interp, int argc, const char **argv);
00304 static int              TestlocaleCmd(ClientData dummy,
00305                             Tcl_Interp *interp, int objc,
00306                             Tcl_Obj *const objv[]);
00307 static int              TestMathFunc(ClientData clientData,
00308                             Tcl_Interp *interp, Tcl_Value *args,
00309                             Tcl_Value *resultPtr);
00310 static int              TestMathFunc2(ClientData clientData,
00311                             Tcl_Interp *interp, Tcl_Value *args,
00312                             Tcl_Value *resultPtr);
00313 static int              TestmainthreadCmd(ClientData dummy,
00314                             Tcl_Interp *interp, int argc, const char **argv);
00315 static int              TestsetmainloopCmd(ClientData dummy,
00316                             Tcl_Interp *interp, int argc, const char **argv);
00317 static int              TestexitmainloopCmd(ClientData dummy,
00318                             Tcl_Interp *interp, int argc, const char **argv);
00319 static int              TestpanicCmd(ClientData dummy,
00320                             Tcl_Interp *interp, int argc, const char **argv);
00321 static int              TestparserObjCmd(ClientData dummy,
00322                             Tcl_Interp *interp, int objc,
00323                             Tcl_Obj *const objv[]);
00324 static int              TestparsevarObjCmd(ClientData dummy,
00325                             Tcl_Interp *interp, int objc,
00326                             Tcl_Obj *const objv[]);
00327 static int              TestparsevarnameObjCmd(ClientData dummy,
00328                             Tcl_Interp *interp, int objc,
00329                             Tcl_Obj *const objv[]);
00330 static int              TestregexpObjCmd(ClientData dummy,
00331                             Tcl_Interp *interp, int objc,
00332                             Tcl_Obj *const objv[]);
00333 static int              TestreturnObjCmd(ClientData dummy,
00334                             Tcl_Interp *interp, int objc,
00335                             Tcl_Obj *const objv[]);
00336 static void             TestregexpXflags(char *string,
00337                             int length, int *cflagsPtr, int *eflagsPtr);
00338 static int              TestsaveresultCmd(ClientData dummy,
00339                             Tcl_Interp *interp, int objc,
00340                             Tcl_Obj *const objv[]);
00341 static void             TestsaveresultFree(char *blockPtr);
00342 static int              TestsetassocdataCmd(ClientData dummy,
00343                             Tcl_Interp *interp, int argc, const char **argv);
00344 static int              TestsetCmd(ClientData dummy,
00345                             Tcl_Interp *interp, int argc, const char **argv);
00346 static int              Testset2Cmd(ClientData dummy,
00347                             Tcl_Interp *interp, int argc, const char **argv);
00348 static int              TestseterrorcodeCmd(ClientData dummy,
00349                             Tcl_Interp *interp, int argc, const char **argv);
00350 static int              TestsetobjerrorcodeCmd(
00351                             ClientData dummy, Tcl_Interp *interp,
00352                             int objc, Tcl_Obj *const objv[]);
00353 static int              TestsetplatformCmd(ClientData dummy,
00354                             Tcl_Interp *interp, int argc, const char **argv);
00355 static int              TeststaticpkgCmd(ClientData dummy,
00356                             Tcl_Interp *interp, int argc, const char **argv);
00357 static int              TesttranslatefilenameCmd(ClientData dummy,
00358                             Tcl_Interp *interp, int argc, const char **argv);
00359 static int              TestupvarCmd(ClientData dummy,
00360                             Tcl_Interp *interp, int argc, const char **argv);
00361 static int              TestWrongNumArgsObjCmd(
00362                             ClientData clientData, Tcl_Interp *interp,
00363                             int objc, Tcl_Obj *const objv[]);
00364 static int              TestGetIndexFromObjStructObjCmd(
00365                             ClientData clientData, Tcl_Interp *interp,
00366                             int objc, Tcl_Obj *const objv[]);
00367 static int              TestChannelCmd(ClientData clientData,
00368                             Tcl_Interp *interp, int argc, const char **argv);
00369 static int              TestChannelEventCmd(ClientData clientData,
00370                             Tcl_Interp *interp, int argc, const char **argv);
00371 static int              TestFilesystemObjCmd(ClientData dummy,
00372                             Tcl_Interp *interp, int objc,
00373                             Tcl_Obj *const objv[]);
00374 static int              TestSimpleFilesystemObjCmd(
00375                             ClientData dummy, Tcl_Interp *interp, int objc,
00376                             Tcl_Obj *const objv[]);
00377 static void             TestReport(const char *cmd, Tcl_Obj *arg1,
00378                             Tcl_Obj *arg2);
00379 static Tcl_Obj *        TestReportGetNativePath(Tcl_Obj *pathPtr);
00380 static int              TestReportStat(Tcl_Obj *path, Tcl_StatBuf *buf);
00381 static int              TestReportAccess(Tcl_Obj *path, int mode);
00382 static Tcl_Channel      TestReportOpenFileChannel(
00383                             Tcl_Interp *interp, Tcl_Obj *fileName,
00384                             int mode, int permissions);
00385 static int              TestReportMatchInDirectory(Tcl_Interp *interp,
00386                             Tcl_Obj *resultPtr, Tcl_Obj *dirPtr,
00387                             const char *pattern, Tcl_GlobTypeData *types);
00388 static int              TestReportChdir(Tcl_Obj *dirName);
00389 static int              TestReportLstat(Tcl_Obj *path, Tcl_StatBuf *buf);
00390 static int              TestReportCopyFile(Tcl_Obj *src, Tcl_Obj *dst);
00391 static int              TestReportDeleteFile(Tcl_Obj *path);
00392 static int              TestReportRenameFile(Tcl_Obj *src, Tcl_Obj *dst);
00393 static int              TestReportCreateDirectory(Tcl_Obj *path);
00394 static int              TestReportCopyDirectory(Tcl_Obj *src,
00395                             Tcl_Obj *dst, Tcl_Obj **errorPtr);
00396 static int              TestReportRemoveDirectory(Tcl_Obj *path,
00397                             int recursive, Tcl_Obj **errorPtr);
00398 static int              TestReportLoadFile(Tcl_Interp *interp,
00399                             Tcl_Obj *fileName, Tcl_LoadHandle *handlePtr,
00400                             Tcl_FSUnloadFileProc **unloadProcPtr);
00401 static Tcl_Obj *        TestReportLink(Tcl_Obj *path,
00402                             Tcl_Obj *to, int linkType);
00403 static const char **    TestReportFileAttrStrings(
00404                             Tcl_Obj *fileName, Tcl_Obj **objPtrRef);
00405 static int              TestReportFileAttrsGet(Tcl_Interp *interp,
00406                             int index, Tcl_Obj *fileName, Tcl_Obj **objPtrRef);
00407 static int              TestReportFileAttrsSet(Tcl_Interp *interp,
00408                             int index, Tcl_Obj *fileName, Tcl_Obj *objPtr);
00409 static int              TestReportUtime(Tcl_Obj *fileName,
00410                             struct utimbuf *tval);
00411 static int              TestReportNormalizePath(Tcl_Interp *interp,
00412                             Tcl_Obj *pathPtr, int nextCheckpoint);
00413 static int              TestReportInFilesystem(Tcl_Obj *pathPtr, ClientData *clientDataPtr);
00414 static void             TestReportFreeInternalRep(ClientData clientData);
00415 static ClientData       TestReportDupInternalRep(ClientData clientData);
00416 
00417 static int              SimpleStat(Tcl_Obj *path, Tcl_StatBuf *buf);
00418 static int              SimpleAccess(Tcl_Obj *path, int mode);
00419 static Tcl_Channel      SimpleOpenFileChannel(Tcl_Interp *interp,
00420                             Tcl_Obj *fileName, int mode, int permissions);
00421 static Tcl_Obj *        SimpleListVolumes(void);
00422 static int              SimplePathInFilesystem(
00423                             Tcl_Obj *pathPtr, ClientData *clientDataPtr);
00424 static Tcl_Obj *        SimpleRedirect(Tcl_Obj *pathPtr);
00425 static int              SimpleMatchInDirectory(
00426                             Tcl_Interp *interp, Tcl_Obj *resultPtr,
00427                             Tcl_Obj *dirPtr, const char *pattern,
00428                             Tcl_GlobTypeData *types);
00429 static int              TestNumUtfCharsCmd(ClientData clientData,
00430                             Tcl_Interp *interp, int objc,
00431                             Tcl_Obj *const objv[]);
00432 static int              TestHashSystemHashCmd(ClientData clientData,
00433                             Tcl_Interp *interp, int objc,
00434                             Tcl_Obj *const objv[]);
00435 
00436 static Tcl_Filesystem testReportingFilesystem = {
00437     "reporting",
00438     sizeof(Tcl_Filesystem),
00439     TCL_FILESYSTEM_VERSION_1,
00440     &TestReportInFilesystem, /* path in */
00441     &TestReportDupInternalRep,
00442     &TestReportFreeInternalRep,
00443     NULL, /* native to norm */
00444     NULL, /* convert to native */
00445     &TestReportNormalizePath,
00446     NULL, /* path type */
00447     NULL, /* separator */
00448     &TestReportStat,
00449     &TestReportAccess,
00450     &TestReportOpenFileChannel,
00451     &TestReportMatchInDirectory,
00452     &TestReportUtime,
00453     &TestReportLink,
00454     NULL /* list volumes */,
00455     &TestReportFileAttrStrings,
00456     &TestReportFileAttrsGet,
00457     &TestReportFileAttrsSet,
00458     &TestReportCreateDirectory,
00459     &TestReportRemoveDirectory,
00460     &TestReportDeleteFile,
00461     &TestReportCopyFile,
00462     &TestReportRenameFile,
00463     &TestReportCopyDirectory,
00464     &TestReportLstat,
00465     &TestReportLoadFile,
00466     NULL /* cwd */,
00467     &TestReportChdir
00468 };
00469 
00470 static Tcl_Filesystem simpleFilesystem = {
00471     "simple",
00472     sizeof(Tcl_Filesystem),
00473     TCL_FILESYSTEM_VERSION_1,
00474     &SimplePathInFilesystem,
00475     NULL,
00476     NULL,
00477     /* No internal to normalized, since we don't create any
00478      * pure 'internal' Tcl_Obj path representations */
00479     NULL,
00480     /* No create native rep function, since we don't use it
00481      * or 'Tcl_FSNewNativePath' */
00482     NULL,
00483     /* Normalize path isn't needed - we assume paths only have
00484      * one representation */
00485     NULL,
00486     NULL,
00487     NULL,
00488     &SimpleStat,
00489     &SimpleAccess,
00490     &SimpleOpenFileChannel,
00491     &SimpleMatchInDirectory,
00492     NULL,
00493     /* We choose not to support symbolic links inside our vfs's */
00494     NULL,
00495     &SimpleListVolumes,
00496     NULL,
00497     NULL,
00498     NULL,
00499     NULL,
00500     NULL,
00501     NULL,
00502     /* No copy file - fallback will occur at Tcl level */
00503     NULL,
00504     /* No rename file - fallback will occur at Tcl level */
00505     NULL,
00506     /* No copy directory - fallback will occur at Tcl level */
00507     NULL,
00508     /* Use stat for lstat */
00509     NULL,
00510     /* No load - fallback on core implementation */
00511     NULL,
00512     /* We don't need a getcwd or chdir - fallback on Tcl's versions */
00513     NULL,
00514     NULL
00515 };
00516 
00517 
00518 /*
00519  * External (platform specific) initialization routine, these declarations
00520  * explicitly don't use EXTERN since this code does not get compiled into the
00521  * library:
00522  */
00523 
00524 extern int              TclplatformtestInit(Tcl_Interp *interp);
00525 extern int              TclThread_Init(Tcl_Interp *interp);
00526 
00527 /*
00528  *----------------------------------------------------------------------
00529  *
00530  * Tcltest_Init --
00531  *
00532  *      This procedure performs application-specific initialization. Most
00533  *      applications, especially those that incorporate additional packages,
00534  *      will have their own version of this procedure.
00535  *
00536  * Results:
00537  *      Returns a standard Tcl completion code, and leaves an error message in
00538  *      the interp's result if an error occurs.
00539  *
00540  * Side effects:
00541  *      Depends on the startup script.
00542  *
00543  *----------------------------------------------------------------------
00544  */
00545 
00546 int
00547 Tcltest_Init(
00548     Tcl_Interp *interp)         /* Interpreter for application. */
00549 {
00550     Tcl_ValueType t3ArgTypes[2];
00551 
00552     Tcl_Obj *listPtr;
00553     Tcl_Obj **objv;
00554     int objc, index;
00555     static const char *specialOptions[] = {
00556         "-appinitprocerror", "-appinitprocdeleteinterp",
00557         "-appinitprocclosestderr", "-appinitprocsetrcfile", NULL
00558     };
00559 
00560     /* TIP #268: Full patchlevel instead of just major.minor */
00561 
00562     if (Tcl_PkgProvide(interp, "Tcltest", TCL_PATCH_LEVEL) == TCL_ERROR) {
00563         return TCL_ERROR;
00564     }
00565 
00566     /*
00567      * Create additional commands and math functions for testing Tcl.
00568      */
00569 
00570     Tcl_CreateCommand(interp, "gettimes", GetTimesCmd, (ClientData) 0, NULL);
00571     Tcl_CreateCommand(interp, "noop", NoopCmd, (ClientData) 0, NULL);
00572     Tcl_CreateObjCommand(interp, "noop", NoopObjCmd, (ClientData) 0, NULL);
00573     Tcl_CreateObjCommand(interp, "testwrongnumargs", TestWrongNumArgsObjCmd,
00574             (ClientData) 0, NULL);
00575     Tcl_CreateObjCommand(interp, "testfilesystem", TestFilesystemObjCmd,
00576             (ClientData) 0, NULL);
00577     Tcl_CreateObjCommand(interp, "testsimplefilesystem", TestSimpleFilesystemObjCmd,
00578             (ClientData) 0, NULL);
00579     Tcl_CreateObjCommand(interp, "testgetindexfromobjstruct",
00580             TestGetIndexFromObjStructObjCmd, (ClientData) 0, NULL);
00581 #ifdef USE_OBSOLETE_FS_HOOKS
00582     Tcl_CreateCommand(interp, "testaccessproc", TestaccessprocCmd, (ClientData) 0,
00583             NULL);
00584     Tcl_CreateCommand(interp, "testopenfilechannelproc",
00585             TestopenfilechannelprocCmd, (ClientData) 0, NULL);
00586     Tcl_CreateCommand(interp, "teststatproc", TeststatprocCmd, (ClientData) 0,
00587             NULL);
00588 #endif
00589     Tcl_CreateCommand(interp, "testasync", TestasyncCmd, (ClientData) 0, NULL);
00590     Tcl_CreateCommand(interp, "testchannel", TestChannelCmd,
00591             (ClientData) 0, NULL);
00592     Tcl_CreateCommand(interp, "testchannelevent", TestChannelEventCmd,
00593             (ClientData) 0, NULL);
00594     Tcl_CreateCommand(interp, "testcmdtoken", TestcmdtokenCmd, (ClientData) 0,
00595             NULL);
00596     Tcl_CreateCommand(interp, "testcmdinfo", TestcmdinfoCmd, (ClientData) 0,
00597             NULL);
00598     Tcl_CreateCommand(interp, "testcmdtrace", TestcmdtraceCmd,
00599             (ClientData) 0, NULL);
00600     Tcl_CreateCommand(interp, "testcreatecommand", TestcreatecommandCmd,
00601             (ClientData) 0, NULL);
00602     Tcl_CreateCommand(interp, "testdcall", TestdcallCmd, (ClientData) 0, NULL);
00603     Tcl_CreateCommand(interp, "testdel", TestdelCmd, (ClientData) 0, NULL);
00604     Tcl_CreateCommand(interp, "testdelassocdata", TestdelassocdataCmd,
00605             (ClientData) 0, NULL);
00606     Tcl_DStringInit(&dstring);
00607     Tcl_CreateCommand(interp, "testdstring", TestdstringCmd, (ClientData) 0,
00608             NULL);
00609     Tcl_CreateObjCommand(interp, "testencoding", TestencodingObjCmd, (ClientData) 0,
00610             NULL);
00611     Tcl_CreateObjCommand(interp, "testevalex", TestevalexObjCmd,
00612             (ClientData) 0, NULL);
00613     Tcl_CreateObjCommand(interp, "testevalobjv", TestevalobjvObjCmd,
00614             (ClientData) 0, NULL);
00615     Tcl_CreateObjCommand(interp, "testevent", TesteventObjCmd,
00616             (ClientData) 0, NULL);
00617     Tcl_CreateCommand(interp, "testexithandler", TestexithandlerCmd,
00618             (ClientData) 0, NULL);
00619     Tcl_CreateCommand(interp, "testexprlong", TestexprlongCmd,
00620             (ClientData) 0, NULL);
00621     Tcl_CreateObjCommand(interp, "testexprlongobj", TestexprlongobjCmd,
00622             (ClientData) 0, NULL);
00623     Tcl_CreateCommand(interp, "testexprdouble", TestexprdoubleCmd,
00624             (ClientData) 0, NULL);
00625     Tcl_CreateObjCommand(interp, "testexprdoubleobj", TestexprdoubleobjCmd,
00626             (ClientData) 0, NULL);
00627     Tcl_CreateObjCommand(interp, "testexprparser", TestexprparserObjCmd,
00628             (ClientData) 0, NULL);
00629     Tcl_CreateCommand(interp, "testexprstring", TestexprstringCmd,
00630             (ClientData) 0, NULL);
00631     Tcl_CreateCommand(interp, "testfevent", TestfeventCmd, (ClientData) 0,
00632             NULL);
00633     Tcl_CreateObjCommand(interp, "testfilelink", TestfilelinkCmd,
00634             (ClientData) 0, NULL);
00635     Tcl_CreateObjCommand(interp, "testfile", TestfileCmd,
00636             (ClientData) 0, NULL);
00637     Tcl_CreateObjCommand(interp, "testhashsystemhash",
00638             TestHashSystemHashCmd, (ClientData) 0, NULL);
00639     Tcl_CreateCommand(interp, "testgetassocdata", TestgetassocdataCmd,
00640             (ClientData) 0, NULL);
00641     Tcl_CreateCommand(interp, "testgetint", TestgetintCmd,
00642             (ClientData) 0, NULL);
00643     Tcl_CreateCommand(interp, "testgetplatform", TestgetplatformCmd,
00644             (ClientData) 0, NULL);
00645     Tcl_CreateObjCommand(interp, "testgetvarfullname",
00646             TestgetvarfullnameCmd, (ClientData) 0, NULL);
00647     Tcl_CreateCommand(interp, "testinterpdelete", TestinterpdeleteCmd,
00648             (ClientData) 0, NULL);
00649     Tcl_CreateCommand(interp, "testlink", TestlinkCmd, (ClientData) 0, NULL);
00650     Tcl_CreateObjCommand(interp, "testlocale", TestlocaleCmd, (ClientData) 0,
00651             NULL);
00652     Tcl_CreateCommand(interp, "testpanic", TestpanicCmd, (ClientData) 0, NULL);
00653     Tcl_CreateObjCommand(interp, "testparser", TestparserObjCmd,
00654             (ClientData) 0, NULL);
00655     Tcl_CreateObjCommand(interp, "testparsevar", TestparsevarObjCmd,
00656             (ClientData) 0, NULL);
00657     Tcl_CreateObjCommand(interp, "testparsevarname", TestparsevarnameObjCmd,
00658             (ClientData) 0, NULL);
00659     Tcl_CreateObjCommand(interp, "testregexp", TestregexpObjCmd,
00660             (ClientData) 0, NULL);
00661     Tcl_CreateObjCommand(interp, "testreturn", TestreturnObjCmd,
00662             (ClientData) 0, NULL);
00663     Tcl_CreateObjCommand(interp, "testsaveresult", TestsaveresultCmd,
00664             (ClientData) 0, NULL);
00665     Tcl_CreateCommand(interp, "testsetassocdata", TestsetassocdataCmd,
00666             (ClientData) 0, NULL);
00667     Tcl_CreateCommand(interp, "testsetnoerr", TestsetCmd,
00668             (ClientData) 0, NULL);
00669     Tcl_CreateCommand(interp, "testseterr", TestsetCmd,
00670             (ClientData) TCL_LEAVE_ERR_MSG, NULL);
00671     Tcl_CreateCommand(interp, "testset2", Testset2Cmd,
00672             (ClientData) TCL_LEAVE_ERR_MSG, NULL);
00673     Tcl_CreateCommand(interp, "testseterrorcode", TestseterrorcodeCmd,
00674             (ClientData) 0, NULL);
00675     Tcl_CreateObjCommand(interp, "testsetobjerrorcode",
00676             TestsetobjerrorcodeCmd, (ClientData) 0, NULL);
00677     Tcl_CreateObjCommand(interp, "testnumutfchars",
00678             TestNumUtfCharsCmd, (ClientData) 0, NULL);
00679     Tcl_CreateCommand(interp, "testsetplatform", TestsetplatformCmd,
00680             (ClientData) 0, NULL);
00681     Tcl_CreateCommand(interp, "teststaticpkg", TeststaticpkgCmd,
00682             (ClientData) 0, NULL);
00683     Tcl_CreateCommand(interp, "testtranslatefilename",
00684             TesttranslatefilenameCmd, (ClientData) 0, NULL);
00685     Tcl_CreateCommand(interp, "testupvar", TestupvarCmd, (ClientData) 0, NULL);
00686     Tcl_CreateMathFunc(interp, "T1", 0, NULL, TestMathFunc, (ClientData) 123);
00687     Tcl_CreateMathFunc(interp, "T2", 0, NULL, TestMathFunc, (ClientData) 345);
00688     Tcl_CreateCommand(interp, "testmainthread", TestmainthreadCmd, (ClientData) 0,
00689             NULL);
00690     Tcl_CreateCommand(interp, "testsetmainloop", TestsetmainloopCmd,
00691             (ClientData) NULL, NULL);
00692     Tcl_CreateCommand(interp, "testexitmainloop", TestexitmainloopCmd,
00693             (ClientData) NULL, NULL);
00694     t3ArgTypes[0] = TCL_EITHER;
00695     t3ArgTypes[1] = TCL_EITHER;
00696     Tcl_CreateMathFunc(interp, "T3", 2, t3ArgTypes, TestMathFunc2,
00697             (ClientData) 0);
00698 
00699 #ifdef TCL_THREADS
00700     if (TclThread_Init(interp) != TCL_OK) {
00701         return TCL_ERROR;
00702     }
00703 #endif
00704 
00705     /*
00706      * Check for special options used in ../tests/main.test
00707      */
00708 
00709     listPtr = Tcl_GetVar2Ex(interp, "argv", NULL, TCL_GLOBAL_ONLY);
00710     if (listPtr != NULL) {
00711         if (Tcl_ListObjGetElements(interp, listPtr, &objc, &objv) != TCL_OK) {
00712             return TCL_ERROR;
00713         }
00714         if (objc && (Tcl_GetIndexFromObj(NULL, objv[0], specialOptions, NULL,
00715                 TCL_EXACT, &index) == TCL_OK)) {
00716             switch (index) {
00717             case 0:
00718                 return TCL_ERROR;
00719             case 1:
00720                 Tcl_DeleteInterp(interp);
00721                 return TCL_ERROR;
00722             case 2: {
00723                 int mode;
00724                 Tcl_UnregisterChannel(interp,
00725                         Tcl_GetChannel(interp, "stderr", &mode));
00726                 return TCL_ERROR;
00727             }
00728             case 3:
00729                 if (objc-1) {
00730                     Tcl_SetVar2Ex(interp, "tcl_rcFileName", NULL, objv[1],
00731                             TCL_GLOBAL_ONLY);
00732                 }
00733                 return TCL_ERROR;
00734             }
00735         }
00736     }
00737 
00738     /*
00739      * And finally add any platform specific test commands.
00740      */
00741 
00742     return TclplatformtestInit(interp);
00743 }
00744 
00745 /*
00746  *----------------------------------------------------------------------
00747  *
00748  * TestasyncCmd --
00749  *
00750  *      This procedure implements the "testasync" command.  It is used
00751  *      to test the asynchronous handler facilities of Tcl.
00752  *
00753  * Results:
00754  *      A standard Tcl result.
00755  *
00756  * Side effects:
00757  *      Creates, deletes, and invokes handlers.
00758  *
00759  *----------------------------------------------------------------------
00760  */
00761 
00762         /* ARGSUSED */
00763 static int
00764 TestasyncCmd(
00765     ClientData dummy,                   /* Not used. */
00766     Tcl_Interp *interp,                 /* Current interpreter. */
00767     int argc,                           /* Number of arguments. */
00768     const char **argv)                  /* Argument strings. */
00769 {
00770     TestAsyncHandler *asyncPtr, *prevPtr;
00771     int id, code;
00772     static int nextId = 1;
00773     char buf[TCL_INTEGER_SPACE];
00774 
00775     if (argc < 2) {
00776         wrongNumArgs:
00777         Tcl_SetResult(interp, "wrong # args", TCL_STATIC);
00778         return TCL_ERROR;
00779     }
00780     if (strcmp(argv[1], "create") == 0) {
00781         if (argc != 3) {
00782             goto wrongNumArgs;
00783         }
00784         asyncPtr = (TestAsyncHandler *) ckalloc(sizeof(TestAsyncHandler));
00785         asyncPtr->id = nextId;
00786         nextId++;
00787         asyncPtr->handler = Tcl_AsyncCreate(AsyncHandlerProc,
00788                 (ClientData) asyncPtr);
00789         asyncPtr->command = (char *) ckalloc((unsigned) (strlen(argv[2]) + 1));
00790         strcpy(asyncPtr->command, argv[2]);
00791         asyncPtr->nextPtr = firstHandler;
00792         firstHandler = asyncPtr;
00793         TclFormatInt(buf, asyncPtr->id);
00794         Tcl_SetResult(interp, buf, TCL_VOLATILE);
00795     } else if (strcmp(argv[1], "delete") == 0) {
00796         if (argc == 2) {
00797             while (firstHandler != NULL) {
00798                 asyncPtr = firstHandler;
00799                 firstHandler = asyncPtr->nextPtr;
00800                 Tcl_AsyncDelete(asyncPtr->handler);
00801                 ckfree(asyncPtr->command);
00802                 ckfree((char *) asyncPtr);
00803             }
00804             return TCL_OK;
00805         }
00806         if (argc != 3) {
00807             goto wrongNumArgs;
00808         }
00809         if (Tcl_GetInt(interp, argv[2], &id) != TCL_OK) {
00810             return TCL_ERROR;
00811         }
00812         for (prevPtr = NULL, asyncPtr = firstHandler; asyncPtr != NULL;
00813                 prevPtr = asyncPtr, asyncPtr = asyncPtr->nextPtr) {
00814             if (asyncPtr->id != id) {
00815                 continue;
00816             }
00817             if (prevPtr == NULL) {
00818                 firstHandler = asyncPtr->nextPtr;
00819             } else {
00820                 prevPtr->nextPtr = asyncPtr->nextPtr;
00821             }
00822             Tcl_AsyncDelete(asyncPtr->handler);
00823             ckfree(asyncPtr->command);
00824             ckfree((char *) asyncPtr);
00825             break;
00826         }
00827     } else if (strcmp(argv[1], "mark") == 0) {
00828         if (argc != 5) {
00829             goto wrongNumArgs;
00830         }
00831         if ((Tcl_GetInt(interp, argv[2], &id) != TCL_OK)
00832                 || (Tcl_GetInt(interp, argv[4], &code) != TCL_OK)) {
00833             return TCL_ERROR;
00834         }
00835         for (asyncPtr = firstHandler; asyncPtr != NULL;
00836                 asyncPtr = asyncPtr->nextPtr) {
00837             if (asyncPtr->id == id) {
00838                 Tcl_AsyncMark(asyncPtr->handler);
00839                 break;
00840             }
00841         }
00842         Tcl_SetResult(interp, (char *)argv[3], TCL_VOLATILE);
00843         return code;
00844 #ifdef TCL_THREADS
00845     } else if (strcmp(argv[1], "marklater") == 0) {
00846         if (argc != 3) {
00847             goto wrongNumArgs;
00848         }
00849         if (Tcl_GetInt(interp, argv[2], &id) != TCL_OK) {
00850             return TCL_ERROR;
00851         }
00852         for (asyncPtr = firstHandler; asyncPtr != NULL;
00853                 asyncPtr = asyncPtr->nextPtr) {
00854             if (asyncPtr->id == id) {
00855                 Tcl_ThreadId threadID;
00856                 if (Tcl_CreateThread(&threadID, AsyncThreadProc,
00857                         (ClientData) asyncPtr, TCL_THREAD_STACK_DEFAULT,
00858                         TCL_THREAD_NOFLAGS) != TCL_OK) {
00859                     Tcl_SetResult(interp, "can't create thread", TCL_STATIC);
00860                     return TCL_ERROR;
00861                 }
00862                 break;
00863             }
00864         }
00865     } else {
00866         Tcl_AppendResult(interp, "bad option \"", argv[1],
00867                 "\": must be create, delete, int, mark, or marklater", NULL);
00868         return TCL_ERROR;
00869 #else /* !TCL_THREADS */
00870     } else {
00871         Tcl_AppendResult(interp, "bad option \"", argv[1],
00872                 "\": must be create, delete, int, or mark", NULL);
00873         return TCL_ERROR;
00874 #endif
00875     }
00876     return TCL_OK;
00877 }
00878 
00879 static int
00880 AsyncHandlerProc(
00881     ClientData clientData,      /* Pointer to TestAsyncHandler structure. */
00882     Tcl_Interp *interp,         /* Interpreter in which command was
00883                                  * executed, or NULL. */
00884     int code)                   /* Current return code from command. */
00885 {
00886     TestAsyncHandler *asyncPtr = (TestAsyncHandler *) clientData;
00887     const char *listArgv[4], *cmd;
00888     char string[TCL_INTEGER_SPACE];
00889 
00890     TclFormatInt(string, code);
00891     listArgv[0] = asyncPtr->command;
00892     listArgv[1] = Tcl_GetString(Tcl_GetObjResult(interp));
00893     listArgv[2] = string;
00894     listArgv[3] = NULL;
00895     cmd = Tcl_Merge(3, listArgv);
00896     if (interp != NULL) {
00897         code = Tcl_Eval(interp, cmd);
00898     } else {
00899         /*
00900          * this should not happen, but by definition of how async handlers are
00901          * invoked, it's possible.  Better error checking is needed here.
00902          */
00903     }
00904     ckfree((char *)cmd);
00905     return code;
00906 }
00907 
00908 /*
00909  *----------------------------------------------------------------------
00910  *
00911  * AsyncThreadProc --
00912  *
00913  *      Delivers an asynchronous event to a handler in another thread.
00914  *
00915  * Results:
00916  *      None.
00917  *
00918  * Side effects:
00919  *      Invokes Tcl_AsyncMark on the handler
00920  *
00921  *----------------------------------------------------------------------
00922  */
00923 
00924 #ifdef TCL_THREADS
00925 static Tcl_ThreadCreateType
00926 AsyncThreadProc(
00927     ClientData clientData)      /* Parameter is a pointer to a
00928                                  * TestAsyncHandler, defined above. */
00929 {
00930     TestAsyncHandler *asyncPtr = clientData;
00931     Tcl_Sleep(1);
00932     Tcl_AsyncMark(asyncPtr->handler);
00933     Tcl_ExitThread(TCL_OK);
00934     TCL_THREAD_CREATE_RETURN;
00935 }
00936 #endif
00937 
00938 /*
00939  *----------------------------------------------------------------------
00940  *
00941  * TestcmdinfoCmd --
00942  *
00943  *      This procedure implements the "testcmdinfo" command.  It is used to
00944  *      test Tcl_GetCommandInfo, Tcl_SetCommandInfo, and command creation and
00945  *      deletion.
00946  *
00947  * Results:
00948  *      A standard Tcl result.
00949  *
00950  * Side effects:
00951  *      Creates and deletes various commands and modifies their data.
00952  *
00953  *----------------------------------------------------------------------
00954  */
00955 
00956         /* ARGSUSED */
00957 static int
00958 TestcmdinfoCmd(
00959     ClientData dummy,           /* Not used. */
00960     Tcl_Interp *interp,         /* Current interpreter. */
00961     int argc,                   /* Number of arguments. */
00962     const char **argv)          /* Argument strings. */
00963 {
00964     Tcl_CmdInfo info;
00965 
00966     if (argc != 3) {
00967         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
00968                 " option cmdName\"", NULL);
00969         return TCL_ERROR;
00970     }
00971     if (strcmp(argv[1], "create") == 0) {
00972         Tcl_CreateCommand(interp, argv[2], CmdProc1, (ClientData) "original",
00973                 CmdDelProc1);
00974     } else if (strcmp(argv[1], "delete") == 0) {
00975         Tcl_DStringInit(&delString);
00976         Tcl_DeleteCommand(interp, argv[2]);
00977         Tcl_DStringResult(interp, &delString);
00978     } else if (strcmp(argv[1], "get") == 0) {
00979         if (Tcl_GetCommandInfo(interp, argv[2], &info) ==0) {
00980             Tcl_SetResult(interp, "??", TCL_STATIC);
00981             return TCL_OK;
00982         }
00983         if (info.proc == CmdProc1) {
00984             Tcl_AppendResult(interp, "CmdProc1", " ",
00985                     (char *) info.clientData, NULL);
00986         } else if (info.proc == CmdProc2) {
00987             Tcl_AppendResult(interp, "CmdProc2", " ",
00988                     (char *) info.clientData, NULL);
00989         } else {
00990             Tcl_AppendResult(interp, "unknown", NULL);
00991         }
00992         if (info.deleteProc == CmdDelProc1) {
00993             Tcl_AppendResult(interp, " CmdDelProc1", " ",
00994                     (char *) info.deleteData, NULL);
00995         } else if (info.deleteProc == CmdDelProc2) {
00996             Tcl_AppendResult(interp, " CmdDelProc2", " ",
00997                     (char *) info.deleteData, NULL);
00998         } else {
00999             Tcl_AppendResult(interp, " unknown", NULL);
01000         }
01001         Tcl_AppendResult(interp, " ", info.namespacePtr->fullName, NULL);
01002         if (info.isNativeObjectProc) {
01003             Tcl_AppendResult(interp, " nativeObjectProc", NULL);
01004         } else {
01005             Tcl_AppendResult(interp, " stringProc", NULL);
01006         }
01007     } else if (strcmp(argv[1], "modify") == 0) {
01008         info.proc = CmdProc2;
01009         info.clientData = (ClientData) "new_command_data";
01010         info.objProc = NULL;
01011         info.objClientData = (ClientData) NULL;
01012         info.deleteProc = CmdDelProc2;
01013         info.deleteData = (ClientData) "new_delete_data";
01014         if (Tcl_SetCommandInfo(interp, argv[2], &info) == 0) {
01015             Tcl_SetResult(interp, "0", TCL_STATIC);
01016         } else {
01017             Tcl_SetResult(interp, "1", TCL_STATIC);
01018         }
01019     } else {
01020         Tcl_AppendResult(interp, "bad option \"", argv[1],
01021                 "\": must be create, delete, get, or modify", NULL);
01022         return TCL_ERROR;
01023     }
01024     return TCL_OK;
01025 }
01026 
01027         /*ARGSUSED*/
01028 static int
01029 CmdProc1(
01030     ClientData clientData,      /* String to return. */
01031     Tcl_Interp *interp,         /* Current interpreter. */
01032     int argc,                   /* Number of arguments. */
01033     const char **argv)          /* Argument strings. */
01034 {
01035     Tcl_AppendResult(interp, "CmdProc1 ", (char *) clientData, NULL);
01036     return TCL_OK;
01037 }
01038 
01039         /*ARGSUSED*/
01040 static int
01041 CmdProc2(
01042     ClientData clientData,      /* String to return. */
01043     Tcl_Interp *interp,         /* Current interpreter. */
01044     int argc,                   /* Number of arguments. */
01045     const char **argv)          /* Argument strings. */
01046 {
01047     Tcl_AppendResult(interp, "CmdProc2 ", (char *) clientData, NULL);
01048     return TCL_OK;
01049 }
01050 
01051 static void
01052 CmdDelProc1(
01053     ClientData clientData)      /* String to save. */
01054 {
01055     Tcl_DStringInit(&delString);
01056     Tcl_DStringAppend(&delString, "CmdDelProc1 ", -1);
01057     Tcl_DStringAppend(&delString, (char *) clientData, -1);
01058 }
01059 
01060 static void
01061 CmdDelProc2(
01062     ClientData clientData)      /* String to save. */
01063 {
01064     Tcl_DStringInit(&delString);
01065     Tcl_DStringAppend(&delString, "CmdDelProc2 ", -1);
01066     Tcl_DStringAppend(&delString, (char *) clientData, -1);
01067 }
01068 
01069 /*
01070  *----------------------------------------------------------------------
01071  *
01072  * TestcmdtokenCmd --
01073  *
01074  *      This procedure implements the "testcmdtoken" command. It is used to
01075  *      test Tcl_Command tokens and procedures such as Tcl_GetCommandFullName.
01076  *
01077  * Results:
01078  *      A standard Tcl result.
01079  *
01080  * Side effects:
01081  *      Creates and deletes various commands and modifies their data.
01082  *
01083  *----------------------------------------------------------------------
01084  */
01085 
01086         /* ARGSUSED */
01087 static int
01088 TestcmdtokenCmd(
01089     ClientData dummy,           /* Not used. */
01090     Tcl_Interp *interp,         /* Current interpreter. */
01091     int argc,                   /* Number of arguments. */
01092     const char **argv)          /* Argument strings. */
01093 {
01094     Tcl_Command token;
01095     int *l;
01096     char buf[30];
01097 
01098     if (argc != 3) {
01099         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
01100                 " option arg\"", NULL);
01101         return TCL_ERROR;
01102     }
01103     if (strcmp(argv[1], "create") == 0) {
01104         token = Tcl_CreateCommand(interp, argv[2], CmdProc1,
01105                 (ClientData) "original", NULL);
01106         sprintf(buf, "%p", (void *)token);
01107         Tcl_SetResult(interp, buf, TCL_VOLATILE);
01108     } else if (strcmp(argv[1], "name") == 0) {
01109         Tcl_Obj *objPtr;
01110 
01111         if (sscanf(argv[2], "%p", &l) != 1) {
01112             Tcl_AppendResult(interp, "bad command token \"", argv[2],
01113                     "\"", NULL);
01114             return TCL_ERROR;
01115         }
01116 
01117         objPtr = Tcl_NewObj();
01118         Tcl_GetCommandFullName(interp, (Tcl_Command) l, objPtr);
01119 
01120         Tcl_AppendElement(interp,
01121                 Tcl_GetCommandName(interp, (Tcl_Command) l));
01122         Tcl_AppendElement(interp, Tcl_GetString(objPtr));
01123         Tcl_DecrRefCount(objPtr);
01124     } else {
01125         Tcl_AppendResult(interp, "bad option \"", argv[1],
01126                 "\": must be create or name", NULL);
01127         return TCL_ERROR;
01128     }
01129     return TCL_OK;
01130 }
01131 
01132 /*
01133  *----------------------------------------------------------------------
01134  *
01135  * TestcmdtraceCmd --
01136  *
01137  *      This procedure implements the "testcmdtrace" command. It is used
01138  *      to test Tcl_CreateTrace and Tcl_DeleteTrace.
01139  *
01140  * Results:
01141  *      A standard Tcl result.
01142  *
01143  * Side effects:
01144  *      Creates and deletes a command trace, and tests the invocation of
01145  *      a procedure by the command trace.
01146  *
01147  *----------------------------------------------------------------------
01148  */
01149 
01150         /* ARGSUSED */
01151 static int
01152 TestcmdtraceCmd(
01153     ClientData dummy,           /* Not used. */
01154     Tcl_Interp *interp,         /* Current interpreter. */
01155     int argc,                   /* Number of arguments. */
01156     const char **argv)          /* Argument strings. */
01157 {
01158     Tcl_DString buffer;
01159     int result;
01160 
01161     if (argc != 3) {
01162         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
01163                 " option script\"", NULL);
01164         return TCL_ERROR;
01165     }
01166 
01167     if (strcmp(argv[1], "tracetest") == 0) {
01168         Tcl_DStringInit(&buffer);
01169         cmdTrace = Tcl_CreateTrace(interp, 50000,
01170                 (Tcl_CmdTraceProc *) CmdTraceProc, (ClientData) &buffer);
01171         result = Tcl_Eval(interp, argv[2]);
01172         if (result == TCL_OK) {
01173             Tcl_ResetResult(interp);
01174             Tcl_AppendResult(interp, Tcl_DStringValue(&buffer), NULL);
01175         }
01176         Tcl_DeleteTrace(interp, cmdTrace);
01177         Tcl_DStringFree(&buffer);
01178     } else if (strcmp(argv[1], "deletetest") == 0) {
01179         /*
01180          * Create a command trace then eval a script to check whether it is
01181          * called. Note that this trace procedure removes itself as a further
01182          * check of the robustness of the trace proc calling code in
01183          * TclExecuteByteCode.
01184          */
01185 
01186         cmdTrace = Tcl_CreateTrace(interp, 50000,
01187                 (Tcl_CmdTraceProc *) CmdTraceDeleteProc, (ClientData) NULL);
01188         Tcl_Eval(interp, argv[2]);
01189     } else if (strcmp(argv[1], "leveltest") == 0) {
01190         Interp *iPtr = (Interp *) interp;
01191         Tcl_DStringInit(&buffer);
01192         cmdTrace = Tcl_CreateTrace(interp, iPtr->numLevels + 4,
01193                 (Tcl_CmdTraceProc *) CmdTraceProc, (ClientData) &buffer);
01194         result = Tcl_Eval(interp, argv[2]);
01195         if (result == TCL_OK) {
01196             Tcl_ResetResult(interp);
01197             Tcl_AppendResult(interp, Tcl_DStringValue(&buffer), NULL);
01198         }
01199         Tcl_DeleteTrace(interp, cmdTrace);
01200         Tcl_DStringFree(&buffer);
01201     } else if (strcmp(argv[1], "resulttest") == 0) {
01202         /* Create an object-based trace, then eval a script. This is used
01203          * to test return codes other than TCL_OK from the trace engine.
01204          */
01205 
01206         static int deleteCalled;
01207 
01208         deleteCalled = 0;
01209         cmdTrace = Tcl_CreateObjTrace(interp, 50000,
01210                 TCL_ALLOW_INLINE_COMPILATION, ObjTraceProc,
01211                 (ClientData) &deleteCalled, ObjTraceDeleteProc);
01212         result = Tcl_Eval(interp, argv[2]);
01213         Tcl_DeleteTrace(interp, cmdTrace);
01214         if (!deleteCalled) {
01215             Tcl_SetResult(interp, "Delete wasn't called", TCL_STATIC);
01216             return TCL_ERROR;
01217         } else {
01218             return result;
01219         }
01220     } else if ( strcmp(argv[1], "doubletest" ) == 0 ) {
01221         Tcl_Trace t1, t2;
01222 
01223         Tcl_DStringInit(&buffer);
01224         t1 = Tcl_CreateTrace(interp, 1,
01225                 (Tcl_CmdTraceProc *) CmdTraceProc, (ClientData) &buffer);
01226         t2 = Tcl_CreateTrace(interp, 50000,
01227                 (Tcl_CmdTraceProc *) CmdTraceProc, (ClientData) &buffer);
01228         result = Tcl_Eval(interp, argv[2]);
01229         if (result == TCL_OK) {
01230             Tcl_ResetResult(interp);
01231             Tcl_AppendResult(interp, Tcl_DStringValue(&buffer), NULL);
01232         }
01233         Tcl_DeleteTrace(interp, t2);
01234         Tcl_DeleteTrace(interp, t1);
01235         Tcl_DStringFree(&buffer);
01236     } else {
01237         Tcl_AppendResult(interp, "bad option \"", argv[1],
01238                 "\": must be tracetest, deletetest, doubletest or resulttest", NULL);
01239         return TCL_ERROR;
01240     }
01241     return TCL_OK;
01242 }
01243 
01244 static void
01245 CmdTraceProc(
01246     ClientData clientData,      /* Pointer to buffer in which the
01247                                  * command and arguments are appended.
01248                                  * Accumulates test result. */
01249     Tcl_Interp *interp,         /* Current interpreter. */
01250     int level,                  /* Current trace level. */
01251     char *command,              /* The command being traced (after
01252                                  * substitutions). */
01253     Tcl_CmdProc *cmdProc,       /* Points to command's command procedure. */
01254     ClientData cmdClientData,   /* Client data associated with command
01255                                  * procedure. */
01256     int argc,                   /* Number of arguments. */
01257     char **argv)                /* Argument strings. */
01258 {
01259     Tcl_DString *bufPtr = (Tcl_DString *) clientData;
01260     int i;
01261 
01262     Tcl_DStringAppendElement(bufPtr, command);
01263 
01264     Tcl_DStringStartSublist(bufPtr);
01265     for (i = 0;  i < argc;  i++) {
01266         Tcl_DStringAppendElement(bufPtr, argv[i]);
01267     }
01268     Tcl_DStringEndSublist(bufPtr);
01269 }
01270 
01271 static void
01272 CmdTraceDeleteProc(
01273     ClientData clientData,      /* Unused. */
01274     Tcl_Interp *interp,         /* Current interpreter. */
01275     int level,                  /* Current trace level. */
01276     char *command,              /* The command being traced (after
01277                                  * substitutions). */
01278     Tcl_CmdProc *cmdProc,       /* Points to command's command procedure. */
01279     ClientData cmdClientData,   /* Client data associated with command
01280                                  * procedure. */
01281     int argc,                   /* Number of arguments. */
01282     char **argv)                /* Argument strings. */
01283 {
01284     /*
01285      * Remove ourselves to test whether calling Tcl_DeleteTrace within a trace
01286      * callback causes the for loop in TclExecuteByteCode that calls traces to
01287      * reference freed memory.
01288      */
01289 
01290     Tcl_DeleteTrace(interp, cmdTrace);
01291 }
01292 
01293 static int
01294 ObjTraceProc(
01295     ClientData clientData,      /* unused */
01296     Tcl_Interp *interp,         /* Tcl interpreter */
01297     int level,                  /* Execution level */
01298     const char *command,        /* Command being executed */
01299     Tcl_Command token,          /* Command information */
01300     int objc,                   /* Parameter count */
01301     Tcl_Obj *const objv[])      /* Parameter list */
01302 {
01303     const char *word = Tcl_GetString(objv[0]);
01304 
01305     if (!strcmp(word, "Error")) {
01306         Tcl_SetObjResult(interp, Tcl_NewStringObj(command, -1));
01307         return TCL_ERROR;
01308     } else if (!strcmp(word, "Break")) {
01309         return TCL_BREAK;
01310     } else if (!strcmp(word, "Continue")) {
01311         return TCL_CONTINUE;
01312     } else if (!strcmp(word, "Return")) {
01313         return TCL_RETURN;
01314     } else if (!strcmp(word, "OtherStatus")) {
01315         return 6;
01316     } else {
01317         return TCL_OK;
01318     }
01319 }
01320 
01321 static void
01322 ObjTraceDeleteProc(
01323     ClientData clientData)
01324 {
01325     int *intPtr = (int *) clientData;
01326     *intPtr = 1;                /* Record that the trace was deleted */
01327 }
01328 
01329 /*
01330  *----------------------------------------------------------------------
01331  *
01332  * TestcreatecommandCmd --
01333  *
01334  *      This procedure implements the "testcreatecommand" command. It is used
01335  *      to test that the Tcl_CreateCommand creates a new command in the
01336  *      namespace specified as part of its name, if any. It also checks that
01337  *      the namespace code ignore single ":"s in the middle or end of a
01338  *      command name.
01339  *
01340  * Results:
01341  *      A standard Tcl result.
01342  *
01343  * Side effects:
01344  *      Creates and deletes two commands ("test_ns_basic::createdcommand"
01345  *      and "value:at:").
01346  *
01347  *----------------------------------------------------------------------
01348  */
01349 
01350 static int
01351 TestcreatecommandCmd(
01352     ClientData dummy,           /* Not used. */
01353     Tcl_Interp *interp,         /* Current interpreter. */
01354     int argc,                   /* Number of arguments. */
01355     const char **argv)          /* Argument strings. */
01356 {
01357     if (argc != 2) {
01358         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
01359                 " option\"", NULL);
01360         return TCL_ERROR;
01361     }
01362     if (strcmp(argv[1], "create") == 0) {
01363         Tcl_CreateCommand(interp, "test_ns_basic::createdcommand",
01364                 CreatedCommandProc, (ClientData) NULL, NULL);
01365     } else if (strcmp(argv[1], "delete") == 0) {
01366         Tcl_DeleteCommand(interp, "test_ns_basic::createdcommand");
01367     } else if (strcmp(argv[1], "create2") == 0) {
01368         Tcl_CreateCommand(interp, "value:at:",
01369                 CreatedCommandProc2, (ClientData) NULL, NULL);
01370     } else if (strcmp(argv[1], "delete2") == 0) {
01371         Tcl_DeleteCommand(interp, "value:at:");
01372     } else {
01373         Tcl_AppendResult(interp, "bad option \"", argv[1],
01374                 "\": must be create, delete, create2, or delete2", NULL);
01375         return TCL_ERROR;
01376     }
01377     return TCL_OK;
01378 }
01379 
01380 static int
01381 CreatedCommandProc(
01382     ClientData clientData,      /* String to return. */
01383     Tcl_Interp *interp,         /* Current interpreter. */
01384     int argc,                   /* Number of arguments. */
01385     const char **argv)          /* Argument strings. */
01386 {
01387     Tcl_CmdInfo info;
01388     int found;
01389 
01390     found = Tcl_GetCommandInfo(interp, "test_ns_basic::createdcommand",
01391             &info);
01392     if (!found) {
01393         Tcl_AppendResult(interp, "CreatedCommandProc could not get command info for test_ns_basic::createdcommand",
01394                 NULL);
01395         return TCL_ERROR;
01396     }
01397     Tcl_AppendResult(interp, "CreatedCommandProc in ",
01398             info.namespacePtr->fullName, NULL);
01399     return TCL_OK;
01400 }
01401 
01402 static int
01403 CreatedCommandProc2(
01404     ClientData clientData,      /* String to return. */
01405     Tcl_Interp *interp,         /* Current interpreter. */
01406     int argc,                   /* Number of arguments. */
01407     const char **argv)          /* Argument strings. */
01408 {
01409     Tcl_CmdInfo info;
01410     int found;
01411 
01412     found = Tcl_GetCommandInfo(interp, "value:at:", &info);
01413     if (!found) {
01414         Tcl_AppendResult(interp, "CreatedCommandProc2 could not get command info for test_ns_basic::createdcommand",
01415                 NULL);
01416         return TCL_ERROR;
01417     }
01418     Tcl_AppendResult(interp, "CreatedCommandProc2 in ",
01419             info.namespacePtr->fullName, NULL);
01420     return TCL_OK;
01421 }
01422 
01423 /*
01424  *----------------------------------------------------------------------
01425  *
01426  * TestdcallCmd --
01427  *
01428  *      This procedure implements the "testdcall" command.  It is used
01429  *      to test Tcl_CallWhenDeleted.
01430  *
01431  * Results:
01432  *      A standard Tcl result.
01433  *
01434  * Side effects:
01435  *      Creates and deletes interpreters.
01436  *
01437  *----------------------------------------------------------------------
01438  */
01439 
01440         /* ARGSUSED */
01441 static int
01442 TestdcallCmd(
01443     ClientData dummy,           /* Not used. */
01444     Tcl_Interp *interp,         /* Current interpreter. */
01445     int argc,                   /* Number of arguments. */
01446     const char **argv)          /* Argument strings. */
01447 {
01448     int i, id;
01449 
01450     delInterp = Tcl_CreateInterp();
01451     Tcl_DStringInit(&delString);
01452     for (i = 1; i < argc; i++) {
01453         if (Tcl_GetInt(interp, argv[i], &id) != TCL_OK) {
01454             return TCL_ERROR;
01455         }
01456         if (id < 0) {
01457             Tcl_DontCallWhenDeleted(delInterp, DelCallbackProc,
01458                     (ClientData) INT2PTR(-id));
01459         } else {
01460             Tcl_CallWhenDeleted(delInterp, DelCallbackProc,
01461                     (ClientData) INT2PTR(id));
01462         }
01463     }
01464     Tcl_DeleteInterp(delInterp);
01465     Tcl_DStringResult(interp, &delString);
01466     return TCL_OK;
01467 }
01468 
01469 /*
01470  * The deletion callback used by TestdcallCmd:
01471  */
01472 
01473 static void
01474 DelCallbackProc(
01475     ClientData clientData,      /* Numerical value to append to delString. */
01476     Tcl_Interp *interp)         /* Interpreter being deleted. */
01477 {
01478     int id = PTR2INT(clientData);
01479     char buffer[TCL_INTEGER_SPACE];
01480 
01481     TclFormatInt(buffer, id);
01482     Tcl_DStringAppendElement(&delString, buffer);
01483     if (interp != delInterp) {
01484         Tcl_DStringAppendElement(&delString, "bogus interpreter argument!");
01485     }
01486 }
01487 
01488 /*
01489  *----------------------------------------------------------------------
01490  *
01491  * TestdelCmd --
01492  *
01493  *      This procedure implements the "testdcall" command.  It is used
01494  *      to test Tcl_CallWhenDeleted.
01495  *
01496  * Results:
01497  *      A standard Tcl result.
01498  *
01499  * Side effects:
01500  *      Creates and deletes interpreters.
01501  *
01502  *----------------------------------------------------------------------
01503  */
01504 
01505         /* ARGSUSED */
01506 static int
01507 TestdelCmd(
01508     ClientData dummy,           /* Not used. */
01509     Tcl_Interp *interp,         /* Current interpreter. */
01510     int argc,                   /* Number of arguments. */
01511     const char **argv)          /* Argument strings. */
01512 {
01513     DelCmd *dPtr;
01514     Tcl_Interp *slave;
01515 
01516     if (argc != 4) {
01517         Tcl_SetResult(interp, "wrong # args", TCL_STATIC);
01518         return TCL_ERROR;
01519     }
01520 
01521     slave = Tcl_GetSlave(interp, argv[1]);
01522     if (slave == NULL) {
01523         return TCL_ERROR;
01524     }
01525 
01526     dPtr = (DelCmd *) ckalloc(sizeof(DelCmd));
01527     dPtr->interp = interp;
01528     dPtr->deleteCmd = (char *) ckalloc((unsigned) (strlen(argv[3]) + 1));
01529     strcpy(dPtr->deleteCmd, argv[3]);
01530 
01531     Tcl_CreateCommand(slave, argv[2], DelCmdProc, (ClientData) dPtr,
01532             DelDeleteProc);
01533     return TCL_OK;
01534 }
01535 
01536 static int
01537 DelCmdProc(
01538     ClientData clientData,      /* String result to return. */
01539     Tcl_Interp *interp,         /* Current interpreter. */
01540     int argc,                   /* Number of arguments. */
01541     const char **argv)          /* Argument strings. */
01542 {
01543     DelCmd *dPtr = (DelCmd *) clientData;
01544 
01545     Tcl_AppendResult(interp, dPtr->deleteCmd, NULL);
01546     ckfree(dPtr->deleteCmd);
01547     ckfree((char *) dPtr);
01548     return TCL_OK;
01549 }
01550 
01551 static void
01552 DelDeleteProc(
01553     ClientData clientData)      /* String command to evaluate. */
01554 {
01555     DelCmd *dPtr = (DelCmd *) clientData;
01556 
01557     Tcl_Eval(dPtr->interp, dPtr->deleteCmd);
01558     Tcl_ResetResult(dPtr->interp);
01559     ckfree(dPtr->deleteCmd);
01560     ckfree((char *) dPtr);
01561 }
01562 
01563 /*
01564  *----------------------------------------------------------------------
01565  *
01566  * TestdelassocdataCmd --
01567  *
01568  *      This procedure implements the "testdelassocdata" command. It is used
01569  *      to test Tcl_DeleteAssocData.
01570  *
01571  * Results:
01572  *      A standard Tcl result.
01573  *
01574  * Side effects:
01575  *      Deletes an association between a key and associated data from an
01576  *      interpreter.
01577  *
01578  *----------------------------------------------------------------------
01579  */
01580 
01581 static int
01582 TestdelassocdataCmd(
01583     ClientData clientData,      /* Not used. */
01584     Tcl_Interp *interp,         /* Current interpreter. */
01585     int argc,                   /* Number of arguments. */
01586     const char **argv)          /* Argument strings. */
01587 {
01588     if (argc != 2) {
01589         Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0],
01590                 " data_key\"", NULL);
01591         return TCL_ERROR;
01592     }
01593     Tcl_DeleteAssocData(interp, argv[1]);
01594     return TCL_OK;
01595 }
01596 
01597 /*
01598  *----------------------------------------------------------------------
01599  *
01600  * TestdstringCmd --
01601  *
01602  *      This procedure implements the "testdstring" command.  It is used
01603  *      to test the dynamic string facilities of Tcl.
01604  *
01605  * Results:
01606  *      A standard Tcl result.
01607  *
01608  * Side effects:
01609  *      Creates, deletes, and invokes handlers.
01610  *
01611  *----------------------------------------------------------------------
01612  */
01613 
01614         /* ARGSUSED */
01615 static int
01616 TestdstringCmd(
01617     ClientData dummy,           /* Not used. */
01618     Tcl_Interp *interp,         /* Current interpreter. */
01619     int argc,                   /* Number of arguments. */
01620     const char **argv)          /* Argument strings. */
01621 {
01622     int count;
01623 
01624     if (argc < 2) {
01625         wrongNumArgs:
01626         Tcl_SetResult(interp, "wrong # args", TCL_STATIC);
01627         return TCL_ERROR;
01628     }
01629     if (strcmp(argv[1], "append") == 0) {
01630         if (argc != 4) {
01631             goto wrongNumArgs;
01632         }
01633         if (Tcl_GetInt(interp, argv[3], &count) != TCL_OK) {
01634             return TCL_ERROR;
01635         }
01636         Tcl_DStringAppend(&dstring, argv[2], count);
01637     } else if (strcmp(argv[1], "element") == 0) {
01638         if (argc != 3) {
01639             goto wrongNumArgs;
01640         }
01641         Tcl_DStringAppendElement(&dstring, argv[2]);
01642     } else if (strcmp(argv[1], "end") == 0) {
01643         if (argc != 2) {
01644             goto wrongNumArgs;
01645         }
01646         Tcl_DStringEndSublist(&dstring);
01647     } else if (strcmp(argv[1], "free") == 0) {
01648         if (argc != 2) {
01649             goto wrongNumArgs;
01650         }
01651         Tcl_DStringFree(&dstring);
01652     } else if (strcmp(argv[1], "get") == 0) {
01653         if (argc != 2) {
01654             goto wrongNumArgs;
01655         }
01656         Tcl_SetResult(interp, Tcl_DStringValue(&dstring), TCL_VOLATILE);
01657     } else if (strcmp(argv[1], "gresult") == 0) {
01658         if (argc != 3) {
01659             goto wrongNumArgs;
01660         }
01661         if (strcmp(argv[2], "staticsmall") == 0) {
01662             Tcl_SetResult(interp, "short", TCL_STATIC);
01663         } else if (strcmp(argv[2], "staticlarge") == 0) {
01664             Tcl_SetResult(interp, "first0 first1 first2 first3 first4 first5 first6 first7 first8 first9\nsecond0 second1 second2 second3 second4 second5 second6 second7 second8 second9\nthird0 third1 third2 third3 third4 third5 third6 third7 third8 third9\nfourth0 fourth1 fourth2 fourth3 fourth4 fourth5 fourth6 fourth7 fourth8 fourth9\nfifth0 fifth1 fifth2 fifth3 fifth4 fifth5 fifth6 fifth7 fifth8 fifth9\nsixth0 sixth1 sixth2 sixth3 sixth4 sixth5 sixth6 sixth7 sixth8 sixth9\nseventh0 seventh1 seventh2 seventh3 seventh4 seventh5 seventh6 seventh7 seventh8 seventh9\n", TCL_STATIC);
01665         } else if (strcmp(argv[2], "free") == 0) {
01666             Tcl_SetResult(interp, (char *) ckalloc(100), TCL_DYNAMIC);
01667             strcpy(interp->result, "This is a malloc-ed string");
01668         } else if (strcmp(argv[2], "special") == 0) {
01669             interp->result = (char *) ckalloc(100);
01670             interp->result += 4;
01671             interp->freeProc = SpecialFree;
01672             strcpy(interp->result, "This is a specially-allocated string");
01673         } else {
01674             Tcl_AppendResult(interp, "bad gresult option \"", argv[2],
01675                     "\": must be staticsmall, staticlarge, free, or special",
01676                     NULL);
01677             return TCL_ERROR;
01678         }
01679         Tcl_DStringGetResult(interp, &dstring);
01680     } else if (strcmp(argv[1], "length") == 0) {
01681         char buf[TCL_INTEGER_SPACE];
01682 
01683         if (argc != 2) {
01684             goto wrongNumArgs;
01685         }
01686         TclFormatInt(buf, Tcl_DStringLength(&dstring));
01687         Tcl_SetResult(interp, buf, TCL_VOLATILE);
01688     } else if (strcmp(argv[1], "result") == 0) {
01689         if (argc != 2) {
01690             goto wrongNumArgs;
01691         }
01692         Tcl_DStringResult(interp, &dstring);
01693     } else if (strcmp(argv[1], "trunc") == 0) {
01694         if (argc != 3) {
01695             goto wrongNumArgs;
01696         }
01697         if (Tcl_GetInt(interp, argv[2], &count) != TCL_OK) {
01698             return TCL_ERROR;
01699         }
01700         Tcl_DStringTrunc(&dstring, count);
01701     } else if (strcmp(argv[1], "start") == 0) {
01702         if (argc != 2) {
01703             goto wrongNumArgs;
01704         }
01705         Tcl_DStringStartSublist(&dstring);
01706     } else {
01707         Tcl_AppendResult(interp, "bad option \"", argv[1],
01708                 "\": must be append, element, end, free, get, length, "
01709                 "result, trunc, or start", NULL);
01710         return TCL_ERROR;
01711     }
01712     return TCL_OK;
01713 }
01714 
01715 /*
01716  * The procedure below is used as a special freeProc to test how well
01717  * Tcl_DStringGetResult handles freeProc's other than free.
01718  */
01719 
01720 static void SpecialFree(blockPtr)
01721     char *blockPtr;                     /* Block to free. */
01722 {
01723     ckfree(blockPtr - 4);
01724 }
01725 
01726 /*
01727  *----------------------------------------------------------------------
01728  *
01729  * TestencodingCmd --
01730  *
01731  *      This procedure implements the "testencoding" command.  It is used
01732  *      to test the encoding package.
01733  *
01734  * Results:
01735  *      A standard Tcl result.
01736  *
01737  * Side effects:
01738  *      Load encodings.
01739  *
01740  *----------------------------------------------------------------------
01741  */
01742 
01743         /* ARGSUSED */
01744 static int
01745 TestencodingObjCmd(
01746     ClientData dummy,           /* Not used. */
01747     Tcl_Interp *interp,         /* Current interpreter. */
01748     int objc,                   /* Number of arguments. */
01749     Tcl_Obj *const objv[])      /* Argument objects. */
01750 {
01751     Tcl_Encoding encoding;
01752     int index, length;
01753     char *string;
01754     TclEncoding *encodingPtr;
01755     static const char *optionStrings[] = {
01756         "create",       "delete",       NULL
01757     };
01758     enum options {
01759         ENC_CREATE,     ENC_DELETE
01760     };
01761 
01762     if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0,
01763             &index) != TCL_OK) {
01764         return TCL_ERROR;
01765     }
01766 
01767     switch ((enum options) index) {
01768     case ENC_CREATE: {
01769         Tcl_EncodingType type;
01770 
01771         if (objc != 5) {
01772             return TCL_ERROR;
01773         }
01774         encodingPtr = (TclEncoding *) ckalloc(sizeof(TclEncoding));
01775         encodingPtr->interp = interp;
01776 
01777         string = Tcl_GetStringFromObj(objv[3], &length);
01778         encodingPtr->toUtfCmd = (char *) ckalloc((unsigned) (length + 1));
01779         memcpy(encodingPtr->toUtfCmd, string, (unsigned) length + 1);
01780 
01781         string = Tcl_GetStringFromObj(objv[4], &length);
01782         encodingPtr->fromUtfCmd = (char *) ckalloc((unsigned) (length + 1));
01783         memcpy(encodingPtr->fromUtfCmd, string, (unsigned) (length + 1));
01784 
01785         string = Tcl_GetStringFromObj(objv[2], &length);
01786 
01787         type.encodingName = string;
01788         type.toUtfProc = EncodingToUtfProc;
01789         type.fromUtfProc = EncodingFromUtfProc;
01790         type.freeProc = EncodingFreeProc;
01791         type.clientData = (ClientData) encodingPtr;
01792         type.nullSize = 1;
01793 
01794         Tcl_CreateEncoding(&type);
01795         break;
01796     }
01797     case ENC_DELETE:
01798         if (objc != 3) {
01799             return TCL_ERROR;
01800         }
01801         encoding = Tcl_GetEncoding(NULL, Tcl_GetString(objv[2]));
01802         Tcl_FreeEncoding(encoding);
01803         Tcl_FreeEncoding(encoding);
01804         break;
01805     }
01806     return TCL_OK;
01807 }
01808 
01809 static int
01810 EncodingToUtfProc(
01811     ClientData clientData,      /* TclEncoding structure. */
01812     const char *src,            /* Source string in specified encoding. */
01813     int srcLen,                 /* Source string length in bytes. */
01814     int flags,                  /* Conversion control flags. */
01815     Tcl_EncodingState *statePtr,/* Current state. */
01816     char *dst,                  /* Output buffer. */
01817     int dstLen,                 /* The maximum length of output buffer. */
01818     int *srcReadPtr,            /* Filled with number of bytes read. */
01819     int *dstWrotePtr,           /* Filled with number of bytes stored. */
01820     int *dstCharsPtr)           /* Filled with number of chars stored. */
01821 {
01822     int len;
01823     TclEncoding *encodingPtr;
01824 
01825     encodingPtr = (TclEncoding *) clientData;
01826     Tcl_GlobalEval(encodingPtr->interp, encodingPtr->toUtfCmd);
01827 
01828     len = strlen(Tcl_GetStringResult(encodingPtr->interp));
01829     if (len > dstLen) {
01830         len = dstLen;
01831     }
01832     memcpy(dst, Tcl_GetStringResult(encodingPtr->interp), (unsigned) len);
01833     Tcl_ResetResult(encodingPtr->interp);
01834 
01835     *srcReadPtr = srcLen;
01836     *dstWrotePtr = len;
01837     *dstCharsPtr = len;
01838     return TCL_OK;
01839 }
01840 
01841 static int
01842 EncodingFromUtfProc(
01843     ClientData clientData,      /* TclEncoding structure. */
01844     const char *src,            /* Source string in specified encoding. */
01845     int srcLen,                 /* Source string length in bytes. */
01846     int flags,                  /* Conversion control flags. */
01847     Tcl_EncodingState *statePtr,/* Current state. */
01848     char *dst,                  /* Output buffer. */
01849     int dstLen,                 /* The maximum length of output buffer. */
01850     int *srcReadPtr,            /* Filled with number of bytes read. */
01851     int *dstWrotePtr,           /* Filled with number of bytes stored. */
01852     int *dstCharsPtr)           /* Filled with number of chars stored. */
01853 {
01854     int len;
01855     TclEncoding *encodingPtr;
01856 
01857     encodingPtr = (TclEncoding *) clientData;
01858     Tcl_GlobalEval(encodingPtr->interp, encodingPtr->fromUtfCmd);
01859 
01860     len = strlen(Tcl_GetStringResult(encodingPtr->interp));
01861     if (len > dstLen) {
01862         len = dstLen;
01863     }
01864     memcpy(dst, Tcl_GetStringResult(encodingPtr->interp), (unsigned) len);
01865     Tcl_ResetResult(encodingPtr->interp);
01866 
01867     *srcReadPtr = srcLen;
01868     *dstWrotePtr = len;
01869     *dstCharsPtr = len;
01870     return TCL_OK;
01871 }
01872 
01873 static void
01874 EncodingFreeProc(
01875     ClientData clientData)      /* ClientData associated with type. */
01876 {
01877     TclEncoding *encodingPtr;
01878 
01879     encodingPtr = (TclEncoding *) clientData;
01880     ckfree((char *) encodingPtr->toUtfCmd);
01881     ckfree((char *) encodingPtr->fromUtfCmd);
01882     ckfree((char *) encodingPtr);
01883 }
01884 
01885 /*
01886  *----------------------------------------------------------------------
01887  *
01888  * TestevalexObjCmd --
01889  *
01890  *      This procedure implements the "testevalex" command.  It is
01891  *      used to test Tcl_EvalEx.
01892  *
01893  * Results:
01894  *      A standard Tcl result.
01895  *
01896  * Side effects:
01897  *      None.
01898  *
01899  *----------------------------------------------------------------------
01900  */
01901 
01902 static int
01903 TestevalexObjCmd(
01904     ClientData dummy,           /* Not used. */
01905     Tcl_Interp *interp,         /* Current interpreter. */
01906     int objc,                   /* Number of arguments. */
01907     Tcl_Obj *const objv[])      /* Argument objects. */
01908 {
01909     int length, flags;
01910     char *script;
01911 
01912     flags = 0;
01913     if (objc == 3) {
01914         char *global = Tcl_GetStringFromObj(objv[2], &length);
01915         if (strcmp(global, "global") != 0) {
01916             Tcl_AppendResult(interp, "bad value \"", global,
01917                     "\": must be global", NULL);
01918             return TCL_ERROR;
01919         }
01920         flags = TCL_EVAL_GLOBAL;
01921     } else if (objc != 2) {
01922         Tcl_WrongNumArgs(interp, 1, objv, "script ?global?");
01923         return TCL_ERROR;
01924     }
01925 
01926     script = Tcl_GetStringFromObj(objv[1], &length);
01927     return Tcl_EvalEx(interp, script, length, flags);
01928 }
01929 
01930 /*
01931  *----------------------------------------------------------------------
01932  *
01933  * TestevalobjvObjCmd --
01934  *
01935  *      This procedure implements the "testevalobjv" command.  It is
01936  *      used to test Tcl_EvalObjv.
01937  *
01938  * Results:
01939  *      A standard Tcl result.
01940  *
01941  * Side effects:
01942  *      None.
01943  *
01944  *----------------------------------------------------------------------
01945  */
01946 
01947 static int
01948 TestevalobjvObjCmd(
01949     ClientData dummy,           /* Not used. */
01950     Tcl_Interp *interp,         /* Current interpreter. */
01951     int objc,                   /* Number of arguments. */
01952     Tcl_Obj *const objv[])      /* Argument objects. */
01953 {
01954     int evalGlobal;
01955 
01956     if (objc < 3) {
01957         Tcl_WrongNumArgs(interp, 1, objv, "global word ?word ...?");
01958         return TCL_ERROR;
01959     }
01960     if (Tcl_GetIntFromObj(interp, objv[1], &evalGlobal) != TCL_OK) {
01961         return TCL_ERROR;
01962     }
01963     return Tcl_EvalObjv(interp, objc-2, objv+2,
01964             (evalGlobal) ? TCL_EVAL_GLOBAL : 0);
01965 }
01966 
01967 /*
01968  *----------------------------------------------------------------------
01969  *
01970  * TesteventObjCmd --
01971  *
01972  *      This procedure implements a 'testevent' command.  The command
01973  *      is used to test event queue management.
01974  *
01975  * The command takes two forms:
01976  *      - testevent queue name position script
01977  *              Queues an event at the given position in the queue, and
01978  *              associates a given name with it (the same name may be
01979  *              associated with multiple events). When the event comes
01980  *              to the head of the queue, executes the given script at
01981  *              global level in the current interp. The position may be
01982  *              one of 'head', 'tail' or 'mark'.
01983  *      - testevent delete name
01984  *              Deletes any events associated with the given name from
01985  *              the queue.
01986  *
01987  * Return value:
01988  *      Returns a standard Tcl result.
01989  *
01990  * Side effects:
01991  *      Manipulates the event queue as directed.
01992  *
01993  *----------------------------------------------------------------------
01994  */
01995 
01996 static int
01997 TesteventObjCmd(
01998     ClientData unused,          /* Not used */
01999     Tcl_Interp *interp,         /* Tcl interpreter */
02000     int objc,                   /* Parameter count */
02001     Tcl_Obj *const objv[])      /* Parameter vector */
02002 {
02003     static const char *subcommands[] = { /* Possible subcommands */
02004         "queue", "delete", NULL
02005     };
02006     int subCmdIndex;            /* Index of the chosen subcommand */
02007     static const char *positions[] = { /* Possible queue positions */
02008         "head", "tail", "mark", NULL
02009     };
02010     int posIndex;               /* Index of the chosen position */
02011     static const Tcl_QueuePosition posNum[] = {
02012                                 /* Interpretation of the chosen position */
02013         TCL_QUEUE_HEAD,
02014         TCL_QUEUE_TAIL,
02015         TCL_QUEUE_MARK
02016     };
02017     TestEvent *ev;              /* Event to be queued */
02018 
02019     if (objc < 2) {
02020         Tcl_WrongNumArgs(interp, 1, objv, "subcommand ?args?");
02021         return TCL_ERROR;
02022     }
02023     if (Tcl_GetIndexFromObj(interp, objv[1], subcommands, "subcommand",
02024             TCL_EXACT, &subCmdIndex) != TCL_OK) {
02025         return TCL_ERROR;
02026     }
02027     switch (subCmdIndex) {
02028     case 0:                     /* queue */
02029         if (objc != 5) {
02030             Tcl_WrongNumArgs(interp, 2, objv, "name position script");
02031             return TCL_ERROR;
02032         }
02033         if (Tcl_GetIndexFromObj(interp, objv[3], positions,
02034                 "position specifier", TCL_EXACT, &posIndex) != TCL_OK) {
02035             return TCL_ERROR;
02036         }
02037         ev = (TestEvent *) ckalloc(sizeof(TestEvent));
02038         ev->header.proc = TesteventProc;
02039         ev->header.nextPtr = NULL;
02040         ev->interp = interp;
02041         ev->command = objv[4];
02042         Tcl_IncrRefCount(ev->command);
02043         ev->tag = objv[2];
02044         Tcl_IncrRefCount(ev->tag);
02045         Tcl_QueueEvent((Tcl_Event *) ev, posNum[posIndex]);
02046         break;
02047 
02048     case 1:                     /* delete */
02049         if (objc != 3) {
02050             Tcl_WrongNumArgs(interp, 2, objv, "name");
02051             return TCL_ERROR;
02052         }
02053         Tcl_DeleteEvents(TesteventDeleteProc, objv[2]);
02054         break;
02055     }
02056 
02057     return TCL_OK;
02058 }
02059 
02060 /*
02061  *----------------------------------------------------------------------
02062  *
02063  * TesteventProc --
02064  *
02065  *      Delivers a test event to the Tcl interpreter as part of event
02066  *      queue testing.
02067  *
02068  * Results:
02069  *      Returns 1 if the event has been serviced, 0 otherwise.
02070  *
02071  * Side effects:
02072  *      Evaluates the event's callback script, so has whatever side effects
02073  *      the callback has.  The return value of the callback script becomes the
02074  *      return value of this function.  If the callback script reports an
02075  *      error, it is reported as a background error.
02076  *
02077  *----------------------------------------------------------------------
02078  */
02079 
02080 static int
02081 TesteventProc(
02082     Tcl_Event *event,           /* Event to deliver */
02083     int flags)                  /* Current flags for Tcl_ServiceEvent */
02084 {
02085     TestEvent *ev = (TestEvent *) event;
02086     Tcl_Interp *interp = ev->interp;
02087     Tcl_Obj *command = ev->command;
02088     int result = Tcl_EvalObjEx(interp, command,
02089             TCL_EVAL_GLOBAL | TCL_EVAL_DIRECT);
02090     int retval;
02091 
02092     if (result != TCL_OK) {
02093         Tcl_AddErrorInfo(interp,
02094                 "    (command bound to \"testevent\" callback)");
02095         Tcl_BackgroundError(interp);
02096         return 1;               /* Avoid looping on errors */
02097     }
02098     if (Tcl_GetBooleanFromObj(interp, Tcl_GetObjResult(interp),
02099             &retval) != TCL_OK) {
02100         Tcl_AddErrorInfo(interp,
02101                 "    (return value from \"testevent\" callback)");
02102         Tcl_BackgroundError(interp);
02103         return 1;
02104     }
02105     if (retval) {
02106         Tcl_DecrRefCount(ev->tag);
02107         Tcl_DecrRefCount(ev->command);
02108     }
02109 
02110     return retval;
02111 }
02112 
02113 /*
02114  *----------------------------------------------------------------------
02115  *
02116  * TesteventDeleteProc --
02117  *
02118  *      Removes some set of events from the queue.
02119  *
02120  * This procedure is used as part of testing event queue management.
02121  *
02122  * Results:
02123  *      Returns 1 if a given event should be deleted, 0 otherwise.
02124  *
02125  * Side effects:
02126  *      None.
02127  *
02128  *----------------------------------------------------------------------
02129  */
02130 
02131 static int
02132 TesteventDeleteProc(
02133     Tcl_Event *event,           /* Event to examine */
02134     ClientData clientData)      /* Tcl_Obj containing the name of the event(s)
02135                                  * to remove */
02136 {
02137     TestEvent *ev;              /* Event to examine */
02138     char *evNameStr;
02139     Tcl_Obj *targetName;        /* Name of the event(s) to delete */
02140     char *targetNameStr;
02141 
02142     if (event->proc != TesteventProc) {
02143         return 0;
02144     }
02145     targetName = (Tcl_Obj *) clientData;
02146     targetNameStr = (char *) Tcl_GetStringFromObj(targetName, NULL);
02147     ev = (TestEvent *) event;
02148     evNameStr = Tcl_GetStringFromObj(ev->tag, NULL);
02149     if (strcmp(evNameStr, targetNameStr) == 0) {
02150         Tcl_DecrRefCount(ev->tag);
02151         Tcl_DecrRefCount(ev->command);
02152         return 1;
02153     } else {
02154         return 0;
02155     }
02156 }
02157 
02158 /*
02159  *----------------------------------------------------------------------
02160  *
02161  * TestexithandlerCmd --
02162  *
02163  *      This procedure implements the "testexithandler" command. It is
02164  *      used to test Tcl_CreateExitHandler and Tcl_DeleteExitHandler.
02165  *
02166  * Results:
02167  *      A standard Tcl result.
02168  *
02169  * Side effects:
02170  *      None.
02171  *
02172  *----------------------------------------------------------------------
02173  */
02174 
02175 static int
02176 TestexithandlerCmd(
02177     ClientData clientData,      /* Not used. */
02178     Tcl_Interp *interp,         /* Current interpreter. */
02179     int argc,                   /* Number of arguments. */
02180     const char **argv)          /* Argument strings. */
02181 {
02182     int value;
02183 
02184     if (argc != 3) {
02185         Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0],
02186                 " create|delete value\"", NULL);
02187         return TCL_ERROR;
02188     }
02189     if (Tcl_GetInt(interp, argv[2], &value) != TCL_OK) {
02190         return TCL_ERROR;
02191     }
02192     if (strcmp(argv[1], "create") == 0) {
02193         Tcl_CreateExitHandler((value & 1) ? ExitProcOdd : ExitProcEven,
02194                 (ClientData) INT2PTR(value));
02195     } else if (strcmp(argv[1], "delete") == 0) {
02196         Tcl_DeleteExitHandler((value & 1) ? ExitProcOdd : ExitProcEven,
02197                 (ClientData) INT2PTR(value));
02198     } else {
02199         Tcl_AppendResult(interp, "bad option \"", argv[1],
02200                 "\": must be create or delete", NULL);
02201         return TCL_ERROR;
02202     }
02203     return TCL_OK;
02204 }
02205 
02206 static void
02207 ExitProcOdd(
02208     ClientData clientData)      /* Integer value to print. */
02209 {
02210     char buf[16 + TCL_INTEGER_SPACE];
02211 
02212     sprintf(buf, "odd %d\n", PTR2INT(clientData));
02213     write(1, buf, strlen(buf));
02214 }
02215 
02216 static void
02217 ExitProcEven(
02218     ClientData clientData)      /* Integer value to print. */
02219 {
02220     char buf[16 + TCL_INTEGER_SPACE];
02221 
02222     sprintf(buf, "even %d\n", PTR2INT(clientData));
02223     write(1, buf, strlen(buf));
02224 }
02225 
02226 /*
02227  *----------------------------------------------------------------------
02228  *
02229  * TestexprlongCmd --
02230  *
02231  *      This procedure verifies that Tcl_ExprLong does not modify the
02232  *      interpreter result if there is no error.
02233  *
02234  * Results:
02235  *      A standard Tcl result.
02236  *
02237  * Side effects:
02238  *      None.
02239  *
02240  *----------------------------------------------------------------------
02241  */
02242 
02243 static int
02244 TestexprlongCmd(
02245     ClientData clientData,      /* Not used. */
02246     Tcl_Interp *interp,         /* Current interpreter. */
02247     int argc,                   /* Number of arguments. */
02248     const char **argv)          /* Argument strings. */
02249 {
02250     long exprResult;
02251     char buf[4 + TCL_INTEGER_SPACE];
02252     int result;
02253 
02254     if (argc != 2) {
02255         Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0],
02256                 " expression\"", NULL);
02257         return TCL_ERROR;
02258     }
02259     Tcl_SetResult(interp, "This is a result", TCL_STATIC);
02260     result = Tcl_ExprLong(interp, argv[1], &exprResult);
02261     if (result != TCL_OK) {
02262         return result;
02263     }
02264     sprintf(buf, ": %ld", exprResult);
02265     Tcl_AppendResult(interp, buf, NULL);
02266     return TCL_OK;
02267 }
02268 
02269 /*
02270  *----------------------------------------------------------------------
02271  *
02272  * TestexprlongobjCmd --
02273  *
02274  *      This procedure verifies that Tcl_ExprLongObj does not modify the
02275  *      interpreter result if there is no error.
02276  *
02277  * Results:
02278  *      A standard Tcl result.
02279  *
02280  * Side effects:
02281  *      None.
02282  *
02283  *----------------------------------------------------------------------
02284  */
02285 
02286 static int
02287 TestexprlongobjCmd(
02288     ClientData clientData,      /* Not used. */
02289     Tcl_Interp *interp,         /* Current interpreter. */
02290     int objc,                   /* Number of arguments. */
02291     Tcl_Obj *const *objv)       /* Argument objects. */
02292 {
02293     long exprResult;
02294     char buf[4 + TCL_INTEGER_SPACE];
02295     int result;
02296 
02297     if (objc != 2) {
02298         Tcl_WrongNumArgs(interp, 1, objv, "expression");
02299         return TCL_ERROR;
02300     }
02301     Tcl_SetResult(interp, "This is a result", TCL_STATIC);
02302     result = Tcl_ExprLongObj(interp, objv[1], &exprResult);
02303     if (result != TCL_OK) {
02304         return result;
02305     }
02306     sprintf(buf, ": %ld", exprResult);
02307     Tcl_AppendResult(interp, buf, NULL);
02308     return TCL_OK;
02309 }
02310 
02311 /*
02312  *----------------------------------------------------------------------
02313  *
02314  * TestexprdoubleCmd --
02315  *
02316  *      This procedure verifies that Tcl_ExprDouble does not modify the
02317  *      interpreter result if there is no error.
02318  *
02319  * Results:
02320  *      A standard Tcl result.
02321  *
02322  * Side effects:
02323  *      None.
02324  *
02325  *----------------------------------------------------------------------
02326  */
02327 
02328 static int
02329 TestexprdoubleCmd(
02330     ClientData clientData,      /* Not used. */
02331     Tcl_Interp *interp,         /* Current interpreter. */
02332     int argc,                   /* Number of arguments. */
02333     const char **argv)          /* Argument strings. */
02334 {
02335     double exprResult;
02336     char buf[4 + TCL_DOUBLE_SPACE];
02337     int result;
02338 
02339     if (argc != 2) {
02340         Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0],
02341                 " expression\"", NULL);
02342         return TCL_ERROR;
02343     }
02344     Tcl_SetResult(interp, "This is a result", TCL_STATIC);
02345     result = Tcl_ExprDouble(interp, argv[1], &exprResult);
02346     if (result != TCL_OK) {
02347         return result;
02348     }
02349     strcpy(buf, ": ");
02350     Tcl_PrintDouble(interp, exprResult, buf+2);
02351     Tcl_AppendResult(interp, buf, NULL);
02352     return TCL_OK;
02353 }
02354 
02355 /*
02356  *----------------------------------------------------------------------
02357  *
02358  * TestexprdoubleobjCmd --
02359  *
02360  *      This procedure verifies that Tcl_ExprLongObj does not modify the
02361  *      interpreter result if there is no error.
02362  *
02363  * Results:
02364  *      A standard Tcl result.
02365  *
02366  * Side effects:
02367  *      None.
02368  *
02369  *----------------------------------------------------------------------
02370  */
02371 
02372 static int
02373 TestexprdoubleobjCmd(
02374     ClientData clientData,      /* Not used. */
02375     Tcl_Interp *interp,         /* Current interpreter. */
02376     int objc,                   /* Number of arguments. */
02377     Tcl_Obj *const *objv)       /* Argument objects. */
02378 {
02379     double exprResult;
02380     char buf[4 + TCL_DOUBLE_SPACE];
02381     int result;
02382 
02383     if (objc != 2) {
02384         Tcl_WrongNumArgs(interp, 1, objv, "expression");
02385         return TCL_ERROR;
02386     }
02387     Tcl_SetResult(interp, "This is a result", TCL_STATIC);
02388     result = Tcl_ExprDoubleObj(interp, objv[1], &exprResult);
02389     if (result != TCL_OK) {
02390         return result;
02391     }
02392     strcpy(buf, ": ");
02393     Tcl_PrintDouble(interp, exprResult, buf+2);
02394     Tcl_AppendResult(interp, buf, NULL);
02395     return TCL_OK;
02396 }
02397 
02398 /*
02399  *----------------------------------------------------------------------
02400  *
02401  * TestexprstringCmd --
02402  *
02403  *      This procedure tests the basic operation of Tcl_ExprString.
02404  *
02405  * Results:
02406  *      A standard Tcl result.
02407  *
02408  * Side effects:
02409  *      None.
02410  *
02411  *----------------------------------------------------------------------
02412  */
02413 
02414 static int
02415 TestexprstringCmd(
02416     ClientData clientData,      /* Not used. */
02417     Tcl_Interp *interp,         /* Current interpreter. */
02418     int argc,                   /* Number of arguments. */
02419     const char **argv)          /* Argument strings. */
02420 {
02421     if (argc != 2) {
02422         Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0],
02423                 " expression\"", NULL);
02424         return TCL_ERROR;
02425     }
02426     return Tcl_ExprString(interp, argv[1]);
02427 }
02428 
02429 /*
02430  *----------------------------------------------------------------------
02431  *
02432  * TestfilelinkCmd --
02433  *
02434  *      This procedure implements the "testfilelink" command.  It is used to
02435  *      test the effects of creating and manipulating filesystem links in Tcl.
02436  *
02437  * Results:
02438  *      A standard Tcl result.
02439  *
02440  * Side effects:
02441  *      May create a link on disk.
02442  *
02443  *----------------------------------------------------------------------
02444  */
02445 
02446 static int
02447 TestfilelinkCmd(
02448     ClientData clientData,      /* Not used. */
02449     Tcl_Interp *interp,         /* Current interpreter. */
02450     int objc,                   /* Number of arguments. */
02451     Tcl_Obj *const objv[])      /* The argument objects. */
02452 {
02453     Tcl_Obj *contents;
02454 
02455     if (objc < 2 || objc > 3) {
02456         Tcl_WrongNumArgs(interp, 1, objv, "source ?target?");
02457         return TCL_ERROR;
02458     }
02459 
02460     if (Tcl_FSConvertToPathType(interp, objv[1]) != TCL_OK) {
02461         return TCL_ERROR;
02462     }
02463 
02464     if (objc == 3) {
02465         /* Create link from source to target */
02466         contents = Tcl_FSLink(objv[1], objv[2],
02467                 TCL_CREATE_SYMBOLIC_LINK|TCL_CREATE_HARD_LINK);
02468         if (contents == NULL) {
02469             Tcl_AppendResult(interp, "could not create link from \"",
02470                     Tcl_GetString(objv[1]), "\" to \"",
02471                     Tcl_GetString(objv[2]), "\": ",
02472                     Tcl_PosixError(interp), NULL);
02473             return TCL_ERROR;
02474         }
02475     } else {
02476         /* Read link */
02477         contents = Tcl_FSLink(objv[1], NULL, 0);
02478         if (contents == NULL) {
02479             Tcl_AppendResult(interp, "could not read link \"",
02480                     Tcl_GetString(objv[1]), "\": ",
02481                     Tcl_PosixError(interp), NULL);
02482             return TCL_ERROR;
02483         }
02484     }
02485     Tcl_SetObjResult(interp, contents);
02486     if (objc == 2) {
02487         /*
02488          * If we are creating a link, this will actually just
02489          * be objv[3], and we don't own it
02490          */
02491         Tcl_DecrRefCount(contents);
02492     }
02493     return TCL_OK;
02494 }
02495 
02496 /*
02497  *----------------------------------------------------------------------
02498  *
02499  * TestgetassocdataCmd --
02500  *
02501  *      This procedure implements the "testgetassocdata" command. It is
02502  *      used to test Tcl_GetAssocData.
02503  *
02504  * Results:
02505  *      A standard Tcl result.
02506  *
02507  * Side effects:
02508  *      None.
02509  *
02510  *----------------------------------------------------------------------
02511  */
02512 
02513 static int
02514 TestgetassocdataCmd(
02515     ClientData clientData,      /* Not used. */
02516     Tcl_Interp *interp,         /* Current interpreter. */
02517     int argc,                   /* Number of arguments. */
02518     const char **argv)          /* Argument strings. */
02519 {
02520     char *res;
02521 
02522     if (argc != 2) {
02523         Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0],
02524                 " data_key\"", NULL);
02525         return TCL_ERROR;
02526     }
02527     res = (char *) Tcl_GetAssocData(interp, argv[1], NULL);
02528     if (res != NULL) {
02529         Tcl_AppendResult(interp, res, NULL);
02530     }
02531     return TCL_OK;
02532 }
02533 
02534 /*
02535  *----------------------------------------------------------------------
02536  *
02537  * TestgetplatformCmd --
02538  *
02539  *      This procedure implements the "testgetplatform" command. It is
02540  *      used to retrievel the value of the tclPlatform global variable.
02541  *
02542  * Results:
02543  *      A standard Tcl result.
02544  *
02545  * Side effects:
02546  *      None.
02547  *
02548  *----------------------------------------------------------------------
02549  */
02550 
02551 static int
02552 TestgetplatformCmd(
02553     ClientData clientData,      /* Not used. */
02554     Tcl_Interp *interp,         /* Current interpreter. */
02555     int argc,                   /* Number of arguments. */
02556     const char **argv)          /* Argument strings. */
02557 {
02558     static const char *platformStrings[] = { "unix", "mac", "windows" };
02559     TclPlatformType *platform;
02560 
02561     platform = TclGetPlatform();
02562 
02563     if (argc != 1) {
02564         Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0],
02565                 NULL);
02566         return TCL_ERROR;
02567     }
02568 
02569     Tcl_AppendResult(interp, platformStrings[*platform], NULL);
02570     return TCL_OK;
02571 }
02572 
02573 /*
02574  *----------------------------------------------------------------------
02575  *
02576  * TestinterpdeleteCmd --
02577  *
02578  *      This procedure tests the code in tclInterp.c that deals with
02579  *      interpreter deletion. It deletes a user-specified interpreter
02580  *      from the hierarchy, and subsequent code checks integrity.
02581  *
02582  * Results:
02583  *      A standard Tcl result.
02584  *
02585  * Side effects:
02586  *      Deletes one or more interpreters.
02587  *
02588  *----------------------------------------------------------------------
02589  */
02590 
02591         /* ARGSUSED */
02592 static int
02593 TestinterpdeleteCmd(
02594     ClientData dummy,           /* Not used. */
02595     Tcl_Interp *interp,         /* Current interpreter. */
02596     int argc,                   /* Number of arguments. */
02597     const char **argv)          /* Argument strings. */
02598 {
02599     Tcl_Interp *slaveToDelete;
02600 
02601     if (argc != 2) {
02602         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
02603                 " path\"", NULL);
02604         return TCL_ERROR;
02605     }
02606     slaveToDelete = Tcl_GetSlave(interp, argv[1]);
02607     if (slaveToDelete == NULL) {
02608         return TCL_ERROR;
02609     }
02610     Tcl_DeleteInterp(slaveToDelete);
02611     return TCL_OK;
02612 }
02613 
02614 /*
02615  *----------------------------------------------------------------------
02616  *
02617  * TestlinkCmd --
02618  *
02619  *      This procedure implements the "testlink" command.  It is used
02620  *      to test Tcl_LinkVar and related library procedures.
02621  *
02622  * Results:
02623  *      A standard Tcl result.
02624  *
02625  * Side effects:
02626  *      Creates and deletes various variable links, plus returns
02627  *      values of the linked variables.
02628  *
02629  *----------------------------------------------------------------------
02630  */
02631 
02632         /* ARGSUSED */
02633 static int
02634 TestlinkCmd(
02635     ClientData dummy,           /* Not used. */
02636     Tcl_Interp *interp,         /* Current interpreter. */
02637     int argc,                   /* Number of arguments. */
02638     const char **argv)          /* Argument strings. */
02639 {
02640     static int intVar = 43;
02641     static int boolVar = 4;
02642     static double realVar = 1.23;
02643     static Tcl_WideInt wideVar = Tcl_LongAsWide(79);
02644     static char *stringVar = NULL;
02645     static char charVar = '@';
02646     static unsigned char ucharVar = 130;
02647     static short shortVar = 3000;
02648     static unsigned short ushortVar = 60000;
02649     static unsigned int uintVar = 0xbeeffeed;
02650     static long longVar = 123456789L;
02651     static unsigned long ulongVar = 3456789012UL;
02652     static float floatVar = 4.5;
02653     static Tcl_WideUInt uwideVar = (Tcl_WideUInt) Tcl_LongAsWide(123);
02654     static int created = 0;
02655     char buffer[2*TCL_DOUBLE_SPACE];
02656     int writable, flag;
02657     Tcl_Obj *tmp;
02658 
02659     if (argc < 2) {
02660         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
02661                 " option ?arg arg arg arg arg arg arg arg arg arg arg arg"
02662                 " arg arg?\"", NULL);
02663         return TCL_ERROR;
02664     }
02665     if (strcmp(argv[1], "create") == 0) {
02666         if (argc != 16) {
02667             Tcl_AppendResult(interp, "wrong # args: should be \"",
02668                 argv[0], " ", argv[1],
02669                 " intRO realRO boolRO stringRO wideRO charRO ucharRO shortRO"
02670                 " ushortRO uintRO longRO ulongRO floatRO uwideRO\"", NULL);
02671             return TCL_ERROR;
02672         }
02673         if (created) {
02674             Tcl_UnlinkVar(interp, "int");
02675             Tcl_UnlinkVar(interp, "real");
02676             Tcl_UnlinkVar(interp, "bool");
02677             Tcl_UnlinkVar(interp, "string");
02678             Tcl_UnlinkVar(interp, "wide");
02679             Tcl_UnlinkVar(interp, "char");
02680             Tcl_UnlinkVar(interp, "uchar");
02681             Tcl_UnlinkVar(interp, "short");
02682             Tcl_UnlinkVar(interp, "ushort");
02683             Tcl_UnlinkVar(interp, "uint");
02684             Tcl_UnlinkVar(interp, "long");
02685             Tcl_UnlinkVar(interp, "ulong");
02686             Tcl_UnlinkVar(interp, "float");
02687             Tcl_UnlinkVar(interp, "uwide");
02688         }
02689         created = 1;
02690         if (Tcl_GetBoolean(interp, argv[2], &writable) != TCL_OK) {
02691             return TCL_ERROR;
02692         }
02693         flag = (writable != 0) ? 0 : TCL_LINK_READ_ONLY;
02694         if (Tcl_LinkVar(interp, "int", (char *) &intVar,
02695                 TCL_LINK_INT | flag) != TCL_OK) {
02696             return TCL_ERROR;
02697         }
02698         if (Tcl_GetBoolean(interp, argv[3], &writable) != TCL_OK) {
02699             return TCL_ERROR;
02700         }
02701         flag = (writable != 0) ? 0 : TCL_LINK_READ_ONLY;
02702         if (Tcl_LinkVar(interp, "real", (char *) &realVar,
02703                 TCL_LINK_DOUBLE | flag) != TCL_OK) {
02704             return TCL_ERROR;
02705         }
02706         if (Tcl_GetBoolean(interp, argv[4], &writable) != TCL_OK) {
02707             return TCL_ERROR;
02708         }
02709         flag = (writable != 0) ? 0 : TCL_LINK_READ_ONLY;
02710         if (Tcl_LinkVar(interp, "bool", (char *) &boolVar,
02711                 TCL_LINK_BOOLEAN | flag) != TCL_OK) {
02712             return TCL_ERROR;
02713         }
02714         if (Tcl_GetBoolean(interp, argv[5], &writable) != TCL_OK) {
02715             return TCL_ERROR;
02716         }
02717         flag = (writable != 0) ? 0 : TCL_LINK_READ_ONLY;
02718         if (Tcl_LinkVar(interp, "string", (char *) &stringVar,
02719                 TCL_LINK_STRING | flag) != TCL_OK) {
02720             return TCL_ERROR;
02721         }
02722         if (Tcl_GetBoolean(interp, argv[6], &writable) != TCL_OK) {
02723             return TCL_ERROR;
02724         }
02725         flag = (writable != 0) ? 0 : TCL_LINK_READ_ONLY;
02726         if (Tcl_LinkVar(interp, "wide", (char *) &wideVar,
02727                         TCL_LINK_WIDE_INT | flag) != TCL_OK) {
02728             return TCL_ERROR;
02729         }
02730         if (Tcl_GetBoolean(interp, argv[7], &writable) != TCL_OK) {
02731             return TCL_ERROR;
02732         }
02733         flag = (writable != 0) ? 0 : TCL_LINK_READ_ONLY;
02734         if (Tcl_LinkVar(interp, "char", (char *) &charVar,
02735                 TCL_LINK_CHAR | flag) != TCL_OK) {
02736             return TCL_ERROR;
02737         }
02738         if (Tcl_GetBoolean(interp, argv[8], &writable) != TCL_OK) {
02739             return TCL_ERROR;
02740         }
02741         flag = (writable != 0) ? 0 : TCL_LINK_READ_ONLY;
02742         if (Tcl_LinkVar(interp, "uchar", (char *) &ucharVar,
02743                 TCL_LINK_UCHAR | flag) != TCL_OK) {
02744             return TCL_ERROR;
02745         }
02746         if (Tcl_GetBoolean(interp, argv[9], &writable) != TCL_OK) {
02747             return TCL_ERROR;
02748         }
02749         flag = (writable != 0) ? 0 : TCL_LINK_READ_ONLY;
02750         if (Tcl_LinkVar(interp, "short", (char *) &shortVar,
02751                 TCL_LINK_SHORT | flag) != TCL_OK) {
02752             return TCL_ERROR;
02753         }
02754         if (Tcl_GetBoolean(interp, argv[10], &writable) != TCL_OK) {
02755             return TCL_ERROR;
02756         }
02757         flag = (writable != 0) ? 0 : TCL_LINK_READ_ONLY;
02758         if (Tcl_LinkVar(interp, "ushort", (char *) &ushortVar,
02759                 TCL_LINK_USHORT | flag) != TCL_OK) {
02760             return TCL_ERROR;
02761         }
02762         if (Tcl_GetBoolean(interp, argv[11], &writable) != TCL_OK) {
02763             return TCL_ERROR;
02764         }
02765         flag = (writable != 0) ? 0 : TCL_LINK_READ_ONLY;
02766         if (Tcl_LinkVar(interp, "uint", (char *) &uintVar,
02767                 TCL_LINK_UINT | flag) != TCL_OK) {
02768             return TCL_ERROR;
02769         }
02770         if (Tcl_GetBoolean(interp, argv[12], &writable) != TCL_OK) {
02771             return TCL_ERROR;
02772         }
02773         flag = (writable != 0) ? 0 : TCL_LINK_READ_ONLY;
02774         if (Tcl_LinkVar(interp, "long", (char *) &longVar,
02775                 TCL_LINK_LONG | flag) != TCL_OK) {
02776             return TCL_ERROR;
02777         }
02778         if (Tcl_GetBoolean(interp, argv[13], &writable) != TCL_OK) {
02779             return TCL_ERROR;
02780         }
02781         flag = (writable != 0) ? 0 : TCL_LINK_READ_ONLY;
02782         if (Tcl_LinkVar(interp, "ulong", (char *) &ulongVar,
02783                 TCL_LINK_ULONG | flag) != TCL_OK) {
02784             return TCL_ERROR;
02785         }
02786         if (Tcl_GetBoolean(interp, argv[14], &writable) != TCL_OK) {
02787             return TCL_ERROR;
02788         }
02789         flag = (writable != 0) ? 0 : TCL_LINK_READ_ONLY;
02790         if (Tcl_LinkVar(interp, "float", (char *) &floatVar,
02791                 TCL_LINK_FLOAT | flag) != TCL_OK) {
02792             return TCL_ERROR;
02793         }
02794         if (Tcl_GetBoolean(interp, argv[15], &writable) != TCL_OK) {
02795             return TCL_ERROR;
02796         }
02797         flag = (writable != 0) ? 0 : TCL_LINK_READ_ONLY;
02798         if (Tcl_LinkVar(interp, "uwide", (char *) &uwideVar,
02799                 TCL_LINK_WIDE_UINT | flag) != TCL_OK) {
02800             return TCL_ERROR;
02801         }
02802 
02803     } else if (strcmp(argv[1], "delete") == 0) {
02804         Tcl_UnlinkVar(interp, "int");
02805         Tcl_UnlinkVar(interp, "real");
02806         Tcl_UnlinkVar(interp, "bool");
02807         Tcl_UnlinkVar(interp, "string");
02808         Tcl_UnlinkVar(interp, "wide");
02809         Tcl_UnlinkVar(interp, "char");
02810         Tcl_UnlinkVar(interp, "uchar");
02811         Tcl_UnlinkVar(interp, "short");
02812         Tcl_UnlinkVar(interp, "ushort");
02813         Tcl_UnlinkVar(interp, "uint");
02814         Tcl_UnlinkVar(interp, "long");
02815         Tcl_UnlinkVar(interp, "ulong");
02816         Tcl_UnlinkVar(interp, "float");
02817         Tcl_UnlinkVar(interp, "uwide");
02818         created = 0;
02819     } else if (strcmp(argv[1], "get") == 0) {
02820         TclFormatInt(buffer, intVar);
02821         Tcl_AppendElement(interp, buffer);
02822         Tcl_PrintDouble(NULL, realVar, buffer);
02823         Tcl_AppendElement(interp, buffer);
02824         TclFormatInt(buffer, boolVar);
02825         Tcl_AppendElement(interp, buffer);
02826         Tcl_AppendElement(interp, (stringVar == NULL) ? "-" : stringVar);
02827         /*
02828          * Wide ints only have an object-based interface.
02829          */
02830         tmp = Tcl_NewWideIntObj(wideVar);
02831         Tcl_AppendElement(interp, Tcl_GetString(tmp));
02832         Tcl_DecrRefCount(tmp);
02833         TclFormatInt(buffer, (int) charVar);
02834         Tcl_AppendElement(interp, buffer);
02835         TclFormatInt(buffer, (int) ucharVar);
02836         Tcl_AppendElement(interp, buffer);
02837         TclFormatInt(buffer, (int) shortVar);
02838         Tcl_AppendElement(interp, buffer);
02839         TclFormatInt(buffer, (int) ushortVar);
02840         Tcl_AppendElement(interp, buffer);
02841         TclFormatInt(buffer, (int) uintVar);
02842         Tcl_AppendElement(interp, buffer);
02843         tmp = Tcl_NewLongObj(longVar);
02844         Tcl_AppendElement(interp, Tcl_GetString(tmp));
02845         Tcl_DecrRefCount(tmp);
02846         tmp = Tcl_NewLongObj((long)ulongVar);
02847         Tcl_AppendElement(interp, Tcl_GetString(tmp));
02848         Tcl_DecrRefCount(tmp);
02849         Tcl_PrintDouble(NULL, (double)floatVar, buffer);
02850         Tcl_AppendElement(interp, buffer);
02851         tmp = Tcl_NewWideIntObj((Tcl_WideInt)uwideVar);
02852         Tcl_AppendElement(interp, Tcl_GetString(tmp));
02853         Tcl_DecrRefCount(tmp);
02854     } else if (strcmp(argv[1], "set") == 0) {
02855         int v;
02856 
02857         if (argc != 16) {
02858             Tcl_AppendResult(interp, "wrong # args: should be \"",
02859                     argv[0], " ", argv[1],
02860                     " intValue realValue boolValue stringValue wideValue"
02861                     " charValue ucharValue shortValue ushortValue uintValue"
02862                     " longValue ulongValue floatValue uwideValue\"", NULL);
02863             return TCL_ERROR;
02864         }
02865         if (argv[2][0] != 0) {
02866             if (Tcl_GetInt(interp, argv[2], &intVar) != TCL_OK) {
02867                 return TCL_ERROR;
02868             }
02869         }
02870         if (argv[3][0] != 0) {
02871             if (Tcl_GetDouble(interp, argv[3], &realVar) != TCL_OK) {
02872                 return TCL_ERROR;
02873             }
02874         }
02875         if (argv[4][0] != 0) {
02876             if (Tcl_GetInt(interp, argv[4], &boolVar) != TCL_OK) {
02877                 return TCL_ERROR;
02878             }
02879         }
02880         if (argv[5][0] != 0) {
02881             if (stringVar != NULL) {
02882                 ckfree(stringVar);
02883             }
02884             if (strcmp(argv[5], "-") == 0) {
02885                 stringVar = NULL;
02886             } else {
02887                 stringVar = (char *) ckalloc((unsigned) (strlen(argv[5]) + 1));
02888                 strcpy(stringVar, argv[5]);
02889             }
02890         }
02891         if (argv[6][0] != 0) {
02892             tmp = Tcl_NewStringObj(argv[6], -1);
02893             if (Tcl_GetWideIntFromObj(interp, tmp, &wideVar) != TCL_OK) {
02894                 Tcl_DecrRefCount(tmp);
02895                 return TCL_ERROR;
02896             }
02897             Tcl_DecrRefCount(tmp);
02898         }
02899         if (argv[7][0]) {
02900             if (Tcl_GetInt(interp, argv[7], &v) != TCL_OK) {
02901                 return TCL_ERROR;
02902             }
02903             charVar = (char) v;
02904         }
02905         if (argv[8][0]) {
02906             if (Tcl_GetInt(interp, argv[8], &v) != TCL_OK) {
02907                 return TCL_ERROR;
02908             }
02909             ucharVar = (unsigned char) v;
02910         }
02911         if (argv[9][0]) {
02912             if (Tcl_GetInt(interp, argv[9], &v) != TCL_OK) {
02913                 return TCL_ERROR;
02914             }
02915             shortVar = (short) v;
02916         }
02917         if (argv[10][0]) {
02918             if (Tcl_GetInt(interp, argv[10], &v) != TCL_OK) {
02919                 return TCL_ERROR;
02920             }
02921             ushortVar = (unsigned short) v;
02922         }
02923         if (argv[11][0]) {
02924             if (Tcl_GetInt(interp, argv[11], &v) != TCL_OK) {
02925                 return TCL_ERROR;
02926             }
02927             uintVar = (unsigned int) v;
02928         }
02929         if (argv[12][0]) {
02930             if (Tcl_GetInt(interp, argv[12], &v) != TCL_OK) {
02931                 return TCL_ERROR;
02932             }
02933             longVar = (long) v;
02934         }
02935         if (argv[13][0]) {
02936             if (Tcl_GetInt(interp, argv[13], &v) != TCL_OK) {
02937                 return TCL_ERROR;
02938             }
02939             ulongVar = (unsigned long) v;
02940         }
02941         if (argv[14][0]) {
02942             double d;
02943             if (Tcl_GetDouble(interp, argv[14], &d) != TCL_OK) {
02944                 return TCL_ERROR;
02945             }
02946             floatVar = (float) d;
02947         }
02948         if (argv[15][0]) {
02949             Tcl_WideInt w;
02950             tmp = Tcl_NewStringObj(argv[15], -1);
02951             if (Tcl_GetWideIntFromObj(interp, tmp, &w) != TCL_OK) {
02952                 Tcl_DecrRefCount(tmp);
02953                 return TCL_ERROR;
02954             }
02955             Tcl_DecrRefCount(tmp);
02956             uwideVar = (Tcl_WideUInt) w;
02957         }
02958     } else if (strcmp(argv[1], "update") == 0) {
02959         int v;
02960 
02961         if (argc != 16) {
02962             Tcl_AppendResult(interp, "wrong # args: should be \"",
02963                     argv[0], " ", argv[1],
02964                     " intValue realValue boolValue stringValue wideValue"
02965                     " charValue ucharValue shortValue ushortValue uintValue"
02966                     " longValue ulongValue floatValue uwideValue\"", NULL);
02967             return TCL_ERROR;
02968         }
02969         if (argv[2][0] != 0) {
02970             if (Tcl_GetInt(interp, argv[2], &intVar) != TCL_OK) {
02971                 return TCL_ERROR;
02972             }
02973             Tcl_UpdateLinkedVar(interp, "int");
02974         }
02975         if (argv[3][0] != 0) {
02976             if (Tcl_GetDouble(interp, argv[3], &realVar) != TCL_OK) {
02977                 return TCL_ERROR;
02978             }
02979             Tcl_UpdateLinkedVar(interp, "real");
02980         }
02981         if (argv[4][0] != 0) {
02982             if (Tcl_GetInt(interp, argv[4], &boolVar) != TCL_OK) {
02983                 return TCL_ERROR;
02984             }
02985             Tcl_UpdateLinkedVar(interp, "bool");
02986         }
02987         if (argv[5][0] != 0) {
02988             if (stringVar != NULL) {
02989                 ckfree(stringVar);
02990             }
02991             if (strcmp(argv[5], "-") == 0) {
02992                 stringVar = NULL;
02993             } else {
02994                 stringVar = (char *) ckalloc((unsigned) (strlen(argv[5]) + 1));
02995                 strcpy(stringVar, argv[5]);
02996             }
02997             Tcl_UpdateLinkedVar(interp, "string");
02998         }
02999         if (argv[6][0] != 0) {
03000             tmp = Tcl_NewStringObj(argv[6], -1);
03001             if (Tcl_GetWideIntFromObj(interp, tmp, &wideVar) != TCL_OK) {
03002                 Tcl_DecrRefCount(tmp);
03003                 return TCL_ERROR;
03004             }
03005             Tcl_DecrRefCount(tmp);
03006             Tcl_UpdateLinkedVar(interp, "wide");
03007         }
03008         if (argv[7][0]) {
03009             if (Tcl_GetInt(interp, argv[7], &v) != TCL_OK) {
03010                 return TCL_ERROR;
03011             }
03012             charVar = (char) v;
03013             Tcl_UpdateLinkedVar(interp, "char");
03014         }
03015         if (argv[8][0]) {
03016             if (Tcl_GetInt(interp, argv[8], &v) != TCL_OK) {
03017                 return TCL_ERROR;
03018             }
03019             ucharVar = (unsigned char) v;
03020             Tcl_UpdateLinkedVar(interp, "uchar");
03021         }
03022         if (argv[9][0]) {
03023             if (Tcl_GetInt(interp, argv[9], &v) != TCL_OK) {
03024                 return TCL_ERROR;
03025             }
03026             shortVar = (short) v;
03027             Tcl_UpdateLinkedVar(interp, "short");
03028         }
03029         if (argv[10][0]) {
03030             if (Tcl_GetInt(interp, argv[10], &v) != TCL_OK) {
03031                 return TCL_ERROR;
03032             }
03033             ushortVar = (unsigned short) v;
03034             Tcl_UpdateLinkedVar(interp, "ushort");
03035         }
03036         if (argv[11][0]) {
03037             if (Tcl_GetInt(interp, argv[11], &v) != TCL_OK) {
03038                 return TCL_ERROR;
03039             }
03040             uintVar = (unsigned int) v;
03041             Tcl_UpdateLinkedVar(interp, "uint");
03042         }
03043         if (argv[12][0]) {
03044             if (Tcl_GetInt(interp, argv[12], &v) != TCL_OK) {
03045                 return TCL_ERROR;
03046             }
03047             longVar = (long) v;
03048             Tcl_UpdateLinkedVar(interp, "long");
03049         }
03050         if (argv[13][0]) {
03051             if (Tcl_GetInt(interp, argv[13], &v) != TCL_OK) {
03052                 return TCL_ERROR;
03053             }
03054             ulongVar = (unsigned long) v;
03055             Tcl_UpdateLinkedVar(interp, "ulong");
03056         }
03057         if (argv[14][0]) {
03058             double d;
03059             if (Tcl_GetDouble(interp, argv[14], &d) != TCL_OK) {
03060                 return TCL_ERROR;
03061             }
03062             floatVar = (float) d;
03063             Tcl_UpdateLinkedVar(interp, "float");
03064         }
03065         if (argv[15][0]) {
03066             Tcl_WideInt w;
03067             tmp = Tcl_NewStringObj(argv[15], -1);
03068             if (Tcl_GetWideIntFromObj(interp, tmp, &w) != TCL_OK) {
03069                 Tcl_DecrRefCount(tmp);
03070                 return TCL_ERROR;
03071             }
03072             Tcl_DecrRefCount(tmp);
03073             uwideVar = (Tcl_WideUInt) w;
03074             Tcl_UpdateLinkedVar(interp, "uwide");
03075         }
03076     } else {
03077         Tcl_AppendResult(interp, "bad option \"", argv[1],
03078                 "\": should be create, delete, get, set, or update", NULL);
03079         return TCL_ERROR;
03080     }
03081     return TCL_OK;
03082 }
03083 
03084 /*
03085  *----------------------------------------------------------------------
03086  *
03087  * TestlocaleCmd --
03088  *
03089  *      This procedure implements the "testlocale" command.  It is used
03090  *      to test the effects of setting different locales in Tcl.
03091  *
03092  * Results:
03093  *      A standard Tcl result.
03094  *
03095  * Side effects:
03096  *      Modifies the current C locale.
03097  *
03098  *----------------------------------------------------------------------
03099  */
03100 
03101 static int
03102 TestlocaleCmd(
03103     ClientData clientData,      /* Not used. */
03104     Tcl_Interp *interp,         /* Current interpreter. */
03105     int objc,                   /* Number of arguments. */
03106     Tcl_Obj *const objv[])      /* The argument objects. */
03107 {
03108     int index;
03109     char *locale;
03110 
03111     static const char *optionStrings[] = {
03112         "ctype", "numeric", "time", "collate", "monetary",
03113         "all",  NULL
03114     };
03115     static int lcTypes[] = {
03116         LC_CTYPE, LC_NUMERIC, LC_TIME, LC_COLLATE, LC_MONETARY,
03117         LC_ALL
03118     };
03119 
03120     /*
03121      * LC_CTYPE, etc. correspond to the indices for the strings.
03122      */
03123 
03124     if (objc < 2 || objc > 3) {
03125         Tcl_WrongNumArgs(interp, 1, objv, "category ?locale?");
03126         return TCL_ERROR;
03127     }
03128 
03129     if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0,
03130             &index) != TCL_OK) {
03131         return TCL_ERROR;
03132     }
03133 
03134     if (objc == 3) {
03135         locale = Tcl_GetString(objv[2]);
03136     } else {
03137         locale = NULL;
03138     }
03139     locale = setlocale(lcTypes[index], locale);
03140     if (locale) {
03141         Tcl_SetStringObj(Tcl_GetObjResult(interp), locale, -1);
03142     }
03143     return TCL_OK;
03144 }
03145 
03146 /*
03147  *----------------------------------------------------------------------
03148  *
03149  * TestMathFunc --
03150  *
03151  *      This is a user-defined math procedure to test out math procedures
03152  *      with no arguments.
03153  *
03154  * Results:
03155  *      A normal Tcl completion code.
03156  *
03157  * Side effects:
03158  *      None.
03159  *
03160  *----------------------------------------------------------------------
03161  */
03162 
03163         /* ARGSUSED */
03164 static int
03165 TestMathFunc(
03166     ClientData clientData,      /* Integer value to return. */
03167     Tcl_Interp *interp,         /* Not used. */
03168     Tcl_Value *args,            /* Not used. */
03169     Tcl_Value *resultPtr)       /* Where to store result. */
03170 {
03171     resultPtr->type = TCL_INT;
03172     resultPtr->intValue = PTR2INT(clientData);
03173     return TCL_OK;
03174 }
03175 
03176 /*
03177  *----------------------------------------------------------------------
03178  *
03179  * TestMathFunc2 --
03180  *
03181  *      This is a user-defined math procedure to test out math procedures
03182  *      that do have arguments, in this case 2.
03183  *
03184  * Results:
03185  *      A normal Tcl completion code.
03186  *
03187  * Side effects:
03188  *      None.
03189  *
03190  *----------------------------------------------------------------------
03191  */
03192 
03193         /* ARGSUSED */
03194 static int
03195 TestMathFunc2(
03196     ClientData clientData,      /* Integer value to return. */
03197     Tcl_Interp *interp,         /* Used to report errors. */
03198     Tcl_Value *args,            /* Points to an array of two Tcl_Value structs
03199                                  * for the two arguments. */
03200     Tcl_Value *resultPtr)       /* Where to store the result. */
03201 {
03202     int result = TCL_OK;
03203 
03204     /*
03205      * Return the maximum of the two arguments with the correct type.
03206      */
03207 
03208     if (args[0].type == TCL_INT) {
03209         int i0 = args[0].intValue;
03210 
03211         if (args[1].type == TCL_INT) {
03212             int i1 = args[1].intValue;
03213 
03214             resultPtr->type = TCL_INT;
03215             resultPtr->intValue = ((i0 > i1)? i0 : i1);
03216         } else if (args[1].type == TCL_DOUBLE) {
03217             double d0 = i0;
03218             double d1 = args[1].doubleValue;
03219 
03220             resultPtr->type = TCL_DOUBLE;
03221             resultPtr->doubleValue = ((d0 > d1)? d0 : d1);
03222         } else if (args[1].type == TCL_WIDE_INT) {
03223             Tcl_WideInt w0 = Tcl_LongAsWide(i0);
03224             Tcl_WideInt w1 = args[1].wideValue;
03225 
03226             resultPtr->type = TCL_WIDE_INT;
03227             resultPtr->wideValue = ((w0 > w1)? w0 : w1);
03228         } else {
03229             Tcl_SetResult(interp, "T3: wrong type for arg 2", TCL_STATIC);
03230             result = TCL_ERROR;
03231         }
03232     } else if (args[0].type == TCL_DOUBLE) {
03233         double d0 = args[0].doubleValue;
03234 
03235         if (args[1].type == TCL_INT) {
03236             double d1 = args[1].intValue;
03237 
03238             resultPtr->type = TCL_DOUBLE;
03239             resultPtr->doubleValue = ((d0 > d1)? d0 : d1);
03240         } else if (args[1].type == TCL_DOUBLE) {
03241             double d1 = args[1].doubleValue;
03242 
03243             resultPtr->type = TCL_DOUBLE;
03244             resultPtr->doubleValue = ((d0 > d1)? d0 : d1);
03245         } else if (args[1].type == TCL_WIDE_INT) {
03246             double d1 = Tcl_WideAsDouble(args[1].wideValue);
03247 
03248             resultPtr->type = TCL_DOUBLE;
03249             resultPtr->doubleValue = ((d0 > d1)? d0 : d1);
03250         } else {
03251             Tcl_SetResult(interp, "T3: wrong type for arg 2", TCL_STATIC);
03252             result = TCL_ERROR;
03253         }
03254     } else if (args[0].type == TCL_WIDE_INT) {
03255         Tcl_WideInt w0 = args[0].wideValue;
03256 
03257         if (args[1].type == TCL_INT) {
03258             Tcl_WideInt w1 = Tcl_LongAsWide(args[1].intValue);
03259 
03260             resultPtr->type = TCL_WIDE_INT;
03261             resultPtr->wideValue = ((w0 > w1)? w0 : w1);
03262         } else if (args[1].type == TCL_DOUBLE) {
03263             double d0 = Tcl_WideAsDouble(w0);
03264             double d1 = args[1].doubleValue;
03265 
03266             resultPtr->type = TCL_DOUBLE;
03267             resultPtr->doubleValue = ((d0 > d1)? d0 : d1);
03268         } else if (args[1].type == TCL_WIDE_INT) {
03269             Tcl_WideInt w1 = args[1].wideValue;
03270 
03271             resultPtr->type = TCL_WIDE_INT;
03272             resultPtr->wideValue = ((w0 > w1)? w0 : w1);
03273         } else {
03274             Tcl_SetResult(interp, "T3: wrong type for arg 2", TCL_STATIC);
03275             result = TCL_ERROR;
03276         }
03277     } else {
03278         Tcl_SetResult(interp, "T3: wrong type for arg 1", TCL_STATIC);
03279         result = TCL_ERROR;
03280     }
03281     return result;
03282 }
03283 
03284 /*
03285  *----------------------------------------------------------------------
03286  *
03287  * CleanupTestSetassocdataTests --
03288  *
03289  *      This function is called when an interpreter is deleted to clean
03290  *      up any data left over from running the testsetassocdata command.
03291  *
03292  * Results:
03293  *      None.
03294  *
03295  * Side effects:
03296  *      Releases storage.
03297  *
03298  *----------------------------------------------------------------------
03299  */
03300         /* ARGSUSED */
03301 static void
03302 CleanupTestSetassocdataTests(
03303     ClientData clientData,      /* Data to be released. */
03304     Tcl_Interp *interp)         /* Interpreter being deleted. */
03305 {
03306     ckfree((char *) clientData);
03307 }
03308 
03309 /*
03310  *----------------------------------------------------------------------
03311  *
03312  * TestparserObjCmd --
03313  *
03314  *      This procedure implements the "testparser" command.  It is
03315  *      used for testing the new Tcl script parser in Tcl 8.1.
03316  *
03317  * Results:
03318  *      A standard Tcl result.
03319  *
03320  * Side effects:
03321  *      None.
03322  *
03323  *----------------------------------------------------------------------
03324  */
03325 
03326 static int
03327 TestparserObjCmd(
03328     ClientData clientData,      /* Not used. */
03329     Tcl_Interp *interp,         /* Current interpreter. */
03330     int objc,                   /* Number of arguments. */
03331     Tcl_Obj *const objv[])      /* The argument objects. */
03332 {
03333     char *script;
03334     int length, dummy;
03335     Tcl_Parse parse;
03336 
03337     if (objc != 3) {
03338         Tcl_WrongNumArgs(interp, 1, objv, "script length");
03339         return TCL_ERROR;
03340     }
03341     script = Tcl_GetStringFromObj(objv[1], &dummy);
03342     if (Tcl_GetIntFromObj(interp, objv[2], &length)) {
03343         return TCL_ERROR;
03344     }
03345     if (length == 0) {
03346         length = dummy;
03347     }
03348     if (Tcl_ParseCommand(interp, script, length, 0, &parse) != TCL_OK) {
03349         Tcl_AddErrorInfo(interp, "\n    (remainder of script: \"");
03350         Tcl_AddErrorInfo(interp, parse.term);
03351         Tcl_AddErrorInfo(interp, "\")");
03352         return TCL_ERROR;
03353     }
03354 
03355     /*
03356      * The parse completed successfully.  Just print out the contents
03357      * of the parse structure into the interpreter's result.
03358      */
03359 
03360     PrintParse(interp, &parse);
03361     Tcl_FreeParse(&parse);
03362     return TCL_OK;
03363 }
03364 
03365 /*
03366  *----------------------------------------------------------------------
03367  *
03368  * TestexprparserObjCmd --
03369  *
03370  *      This procedure implements the "testexprparser" command.  It is
03371  *      used for testing the new Tcl expression parser in Tcl 8.1.
03372  *
03373  * Results:
03374  *      A standard Tcl result.
03375  *
03376  * Side effects:
03377  *      None.
03378  *
03379  *----------------------------------------------------------------------
03380  */
03381 
03382 static int
03383 TestexprparserObjCmd(
03384     ClientData clientData,      /* Not used. */
03385     Tcl_Interp *interp,         /* Current interpreter. */
03386     int objc,                   /* Number of arguments. */
03387     Tcl_Obj *const objv[])      /* The argument objects. */
03388 {
03389     char *script;
03390     int length, dummy;
03391     Tcl_Parse parse;
03392 
03393     if (objc != 3) {
03394         Tcl_WrongNumArgs(interp, 1, objv, "expr length");
03395         return TCL_ERROR;
03396     }
03397     script = Tcl_GetStringFromObj(objv[1], &dummy);
03398     if (Tcl_GetIntFromObj(interp, objv[2], &length)) {
03399         return TCL_ERROR;
03400     }
03401     if (length == 0) {
03402         length = dummy;
03403     }
03404     parse.commentStart = NULL;
03405     parse.commentSize = 0;
03406     parse.commandStart = NULL;
03407     parse.commandSize = 0;
03408     if (Tcl_ParseExpr(interp, script, length, &parse) != TCL_OK) {
03409         Tcl_AddErrorInfo(interp, "\n    (remainder of expr: \"");
03410         Tcl_AddErrorInfo(interp, parse.term);
03411         Tcl_AddErrorInfo(interp, "\")");
03412         return TCL_ERROR;
03413     }
03414 
03415     /*
03416      * The parse completed successfully.  Just print out the contents
03417      * of the parse structure into the interpreter's result.
03418      */
03419 
03420     PrintParse(interp, &parse);
03421     Tcl_FreeParse(&parse);
03422     return TCL_OK;
03423 }
03424 
03425 /*
03426  *----------------------------------------------------------------------
03427  *
03428  * PrintParse --
03429  *
03430  *      This procedure prints out the contents of a Tcl_Parse structure
03431  *      in the result of an interpreter.
03432  *
03433  * Results:
03434  *      Interp's result is set to a prettily formatted version of the
03435  *      contents of parsePtr.
03436  *
03437  * Side effects:
03438  *      None.
03439  *
03440  *----------------------------------------------------------------------
03441  */
03442 
03443 static void
03444 PrintParse(
03445     Tcl_Interp *interp,         /* Interpreter whose result is to be set to
03446                                  * the contents of a parse structure. */
03447     Tcl_Parse *parsePtr)        /* Parse structure to print out. */
03448 {
03449     Tcl_Obj *objPtr;
03450     char *typeString;
03451     Tcl_Token *tokenPtr;
03452     int i;
03453 
03454     objPtr = Tcl_GetObjResult(interp);
03455     if (parsePtr->commentSize > 0) {
03456         Tcl_ListObjAppendElement(NULL, objPtr,
03457                 Tcl_NewStringObj(parsePtr->commentStart,
03458                         parsePtr->commentSize));
03459     } else {
03460         Tcl_ListObjAppendElement(NULL, objPtr, Tcl_NewStringObj("-", 1));
03461     }
03462     Tcl_ListObjAppendElement(NULL, objPtr,
03463             Tcl_NewStringObj(parsePtr->commandStart, parsePtr->commandSize));
03464     Tcl_ListObjAppendElement(NULL, objPtr,
03465             Tcl_NewIntObj(parsePtr->numWords));
03466     for (i = 0; i < parsePtr->numTokens; i++) {
03467         tokenPtr = &parsePtr->tokenPtr[i];
03468         switch (tokenPtr->type) {
03469         case TCL_TOKEN_EXPAND_WORD:
03470             typeString = "expand";
03471             break;
03472         case TCL_TOKEN_WORD:
03473             typeString = "word";
03474             break;
03475         case TCL_TOKEN_SIMPLE_WORD:
03476             typeString = "simple";
03477             break;
03478         case TCL_TOKEN_TEXT:
03479             typeString = "text";
03480             break;
03481         case TCL_TOKEN_BS:
03482             typeString = "backslash";
03483             break;
03484         case TCL_TOKEN_COMMAND:
03485             typeString = "command";
03486             break;
03487         case TCL_TOKEN_VARIABLE:
03488             typeString = "variable";
03489             break;
03490         case TCL_TOKEN_SUB_EXPR:
03491             typeString = "subexpr";
03492             break;
03493         case TCL_TOKEN_OPERATOR:
03494             typeString = "operator";
03495             break;
03496         default:
03497             typeString = "??";
03498             break;
03499         }
03500         Tcl_ListObjAppendElement(NULL, objPtr,
03501                 Tcl_NewStringObj(typeString, -1));
03502         Tcl_ListObjAppendElement(NULL, objPtr,
03503                 Tcl_NewStringObj(tokenPtr->start, tokenPtr->size));
03504         Tcl_ListObjAppendElement(NULL, objPtr,
03505                 Tcl_NewIntObj(tokenPtr->numComponents));
03506     }
03507     Tcl_ListObjAppendElement(NULL, objPtr,
03508             Tcl_NewStringObj(parsePtr->commandStart + parsePtr->commandSize,
03509             -1));
03510 }
03511 
03512 /*
03513  *----------------------------------------------------------------------
03514  *
03515  * TestparsevarObjCmd --
03516  *
03517  *      This procedure implements the "testparsevar" command.  It is
03518  *      used for testing Tcl_ParseVar.
03519  *
03520  * Results:
03521  *      A standard Tcl result.
03522  *
03523  * Side effects:
03524  *      None.
03525  *
03526  *----------------------------------------------------------------------
03527  */
03528 
03529 static int
03530 TestparsevarObjCmd(
03531     ClientData clientData,      /* Not used. */
03532     Tcl_Interp *interp,         /* Current interpreter. */
03533     int objc,                   /* Number of arguments. */
03534     Tcl_Obj *const objv[])      /* The argument objects. */
03535 {
03536     const char *value, *name, *termPtr;
03537 
03538     if (objc != 2) {
03539         Tcl_WrongNumArgs(interp, 1, objv, "varName");
03540         return TCL_ERROR;
03541     }
03542     name = Tcl_GetString(objv[1]);
03543     value = Tcl_ParseVar(interp, name, &termPtr);
03544     if (value == NULL) {
03545         return TCL_ERROR;
03546     }
03547 
03548     Tcl_AppendElement(interp, value);
03549     Tcl_AppendElement(interp, termPtr);
03550     return TCL_OK;
03551 }
03552 
03553 /*
03554  *----------------------------------------------------------------------
03555  *
03556  * TestparsevarnameObjCmd --
03557  *
03558  *      This procedure implements the "testparsevarname" command.  It is
03559  *      used for testing the new Tcl script parser in Tcl 8.1.
03560  *
03561  * Results:
03562  *      A standard Tcl result.
03563  *
03564  * Side effects:
03565  *      None.
03566  *
03567  *----------------------------------------------------------------------
03568  */
03569 
03570 static int
03571 TestparsevarnameObjCmd(
03572     ClientData clientData,      /* Not used. */
03573     Tcl_Interp *interp,         /* Current interpreter. */
03574     int objc,                   /* Number of arguments. */
03575     Tcl_Obj *const objv[])      /* The argument objects. */
03576 {
03577     char *script;
03578     int append, length, dummy;
03579     Tcl_Parse parse;
03580 
03581     if (objc != 4) {
03582         Tcl_WrongNumArgs(interp, 1, objv, "script length append");
03583         return TCL_ERROR;
03584     }
03585     script = Tcl_GetStringFromObj(objv[1], &dummy);
03586     if (Tcl_GetIntFromObj(interp, objv[2], &length)) {
03587         return TCL_ERROR;
03588     }
03589     if (length == 0) {
03590         length = dummy;
03591     }
03592     if (Tcl_GetIntFromObj(interp, objv[3], &append)) {
03593         return TCL_ERROR;
03594     }
03595     if (Tcl_ParseVarName(interp, script, length, &parse, append) != TCL_OK) {
03596         Tcl_AddErrorInfo(interp, "\n    (remainder of script: \"");
03597         Tcl_AddErrorInfo(interp, parse.term);
03598         Tcl_AddErrorInfo(interp, "\")");
03599         return TCL_ERROR;
03600     }
03601 
03602     /*
03603      * The parse completed successfully.  Just print out the contents
03604      * of the parse structure into the interpreter's result.
03605      */
03606 
03607     parse.commentSize = 0;
03608     parse.commandStart = script + parse.tokenPtr->size;
03609     parse.commandSize = 0;
03610     PrintParse(interp, &parse);
03611     Tcl_FreeParse(&parse);
03612     return TCL_OK;
03613 }
03614 
03615 /*
03616  *----------------------------------------------------------------------
03617  *
03618  * TestregexpObjCmd --
03619  *
03620  *      This procedure implements the "testregexp" command. It is used to give
03621  *      a direct interface for regexp flags. It's identical to
03622  *      Tcl_RegexpObjCmd except for the -xflags option, and the consequences
03623  *      thereof (including the REG_EXPECT kludge).
03624  *
03625  * Results:
03626  *      A standard Tcl result.
03627  *
03628  * Side effects:
03629  *      See the user documentation.
03630  *
03631  *----------------------------------------------------------------------
03632  */
03633 
03634         /* ARGSUSED */
03635 static int
03636 TestregexpObjCmd(
03637     ClientData dummy,           /* Not used. */
03638     Tcl_Interp *interp,         /* Current interpreter. */
03639     int objc,                   /* Number of arguments. */
03640     Tcl_Obj *const objv[])      /* Argument objects. */
03641 {
03642     int i, ii, indices, stringLength, match, about;
03643     int hasxflags, cflags, eflags;
03644     Tcl_RegExp regExpr;
03645     char *string;
03646     Tcl_Obj *objPtr;
03647     Tcl_RegExpInfo info;
03648     static const char *options[] = {
03649         "-indices",     "-nocase",      "-about",       "-expanded",
03650         "-line",        "-linestop",    "-lineanchor",
03651         "-xflags",
03652         "--",           NULL
03653     };
03654     enum options {
03655         REGEXP_INDICES, REGEXP_NOCASE,  REGEXP_ABOUT,   REGEXP_EXPANDED,
03656         REGEXP_MULTI,   REGEXP_NOCROSS, REGEXP_NEWL,
03657         REGEXP_XFLAGS,
03658         REGEXP_LAST
03659     };
03660 
03661     indices = 0;
03662     about = 0;
03663     cflags = REG_ADVANCED;
03664     eflags = 0;
03665     hasxflags = 0;
03666 
03667     for (i = 1; i < objc; i++) {
03668         char *name;
03669         int index;
03670 
03671         name = Tcl_GetString(objv[i]);
03672         if (name[0] != '-') {
03673             break;
03674         }
03675         if (Tcl_GetIndexFromObj(interp, objv[i], options, "switch", TCL_EXACT,
03676                 &index) != TCL_OK) {
03677             return TCL_ERROR;
03678         }
03679         switch ((enum options) index) {
03680         case REGEXP_INDICES:
03681             indices = 1;
03682             break;
03683         case REGEXP_NOCASE:
03684             cflags |= REG_ICASE;
03685             break;
03686         case REGEXP_ABOUT:
03687             about = 1;
03688             break;
03689         case REGEXP_EXPANDED:
03690             cflags |= REG_EXPANDED;
03691             break;
03692         case REGEXP_MULTI:
03693             cflags |= REG_NEWLINE;
03694             break;
03695         case REGEXP_NOCROSS:
03696             cflags |= REG_NLSTOP;
03697             break;
03698         case REGEXP_NEWL:
03699             cflags |= REG_NLANCH;
03700             break;
03701         case REGEXP_XFLAGS:
03702             hasxflags = 1;
03703             break;
03704         case REGEXP_LAST:
03705             i++;
03706             goto endOfForLoop;
03707         }
03708     }
03709 
03710   endOfForLoop:
03711     if (objc - i < hasxflags + 2 - about) {
03712         Tcl_WrongNumArgs(interp, 1, objv,
03713                 "?switches? exp string ?matchVar? ?subMatchVar subMatchVar ...?");
03714         return TCL_ERROR;
03715     }
03716     objc -= i;
03717     objv += i;
03718 
03719     if (hasxflags) {
03720         string = Tcl_GetStringFromObj(objv[0], &stringLength);
03721         TestregexpXflags(string, stringLength, &cflags, &eflags);
03722         objc--;
03723         objv++;
03724     }
03725 
03726     regExpr = Tcl_GetRegExpFromObj(interp, objv[0], cflags);
03727     if (regExpr == NULL) {
03728         return TCL_ERROR;
03729     }
03730 
03731     if (about) {
03732         if (TclRegAbout(interp, regExpr) < 0) {
03733             return TCL_ERROR;
03734         }
03735         return TCL_OK;
03736     }
03737 
03738     objPtr = objv[1];
03739     match = Tcl_RegExpExecObj(interp, regExpr, objPtr, 0 /* offset */,
03740             objc-2 /* nmatches */, eflags);
03741 
03742     if (match < 0) {
03743         return TCL_ERROR;
03744     }
03745     if (match == 0) {
03746         /*
03747          * Set the interpreter's object result to an integer object w/
03748          * value 0.
03749          */
03750 
03751         Tcl_SetIntObj(Tcl_GetObjResult(interp), 0);
03752         if (objc > 2 && (cflags&REG_EXPECT) && indices) {
03753             char *varName;
03754             const char *value;
03755             int start, end;
03756             char resinfo[TCL_INTEGER_SPACE * 2];
03757 
03758             varName = Tcl_GetString(objv[2]);
03759             TclRegExpRangeUniChar(regExpr, -1, &start, &end);
03760             sprintf(resinfo, "%d %d", start, end-1);
03761             value = Tcl_SetVar(interp, varName, resinfo, 0);
03762             if (value == NULL) {
03763                 Tcl_AppendResult(interp, "couldn't set variable \"",
03764                         varName, "\"", NULL);
03765                 return TCL_ERROR;
03766             }
03767         } else if (cflags & TCL_REG_CANMATCH) {
03768             char *varName;
03769             const char *value;
03770             char resinfo[TCL_INTEGER_SPACE * 2];
03771 
03772             Tcl_RegExpGetInfo(regExpr, &info);
03773             varName = Tcl_GetString(objv[2]);
03774             sprintf(resinfo, "%ld", info.extendStart);
03775             value = Tcl_SetVar(interp, varName, resinfo, 0);
03776             if (value == NULL) {
03777                 Tcl_AppendResult(interp, "couldn't set variable \"",
03778                         varName, "\"", NULL);
03779                 return TCL_ERROR;
03780             }
03781         }
03782         return TCL_OK;
03783     }
03784 
03785     /*
03786      * If additional variable names have been specified, return
03787      * index information in those variables.
03788      */
03789 
03790     objc -= 2;
03791     objv += 2;
03792 
03793     Tcl_RegExpGetInfo(regExpr, &info);
03794     for (i = 0; i < objc; i++) {
03795         int start, end;
03796         Tcl_Obj *newPtr, *varPtr, *valuePtr;
03797 
03798         varPtr = objv[i];
03799         ii = ((cflags&REG_EXPECT) && i == objc-1) ? -1 : i;
03800         if (indices) {
03801             Tcl_Obj *objs[2];
03802 
03803             if (ii == -1) {
03804                 TclRegExpRangeUniChar(regExpr, ii, &start, &end);
03805             } else if (ii > info.nsubs) {
03806                 start = -1;
03807                 end = -1;
03808             } else {
03809                 start = info.matches[ii].start;
03810                 end = info.matches[ii].end;
03811             }
03812 
03813             /*
03814              * Adjust index so it refers to the last character in the match
03815              * instead of the first character after the match.
03816              */
03817 
03818             if (end >= 0) {
03819                 end--;
03820             }
03821 
03822             objs[0] = Tcl_NewLongObj(start);
03823             objs[1] = Tcl_NewLongObj(end);
03824 
03825             newPtr = Tcl_NewListObj(2, objs);
03826         } else {
03827             if (ii == -1) {
03828                 TclRegExpRangeUniChar(regExpr, ii, &start, &end);
03829                 newPtr = Tcl_GetRange(objPtr, start, end);
03830             } else if (ii > info.nsubs) {
03831                 newPtr = Tcl_NewObj();
03832             } else {
03833                 newPtr = Tcl_GetRange(objPtr, info.matches[ii].start,
03834                         info.matches[ii].end - 1);
03835             }
03836         }
03837         valuePtr = Tcl_ObjSetVar2(interp, varPtr, NULL, newPtr, 0);
03838         if (valuePtr == NULL) {
03839             Tcl_AppendResult(interp, "couldn't set variable \"",
03840                     Tcl_GetString(varPtr), "\"", NULL);
03841             return TCL_ERROR;
03842         }
03843     }
03844 
03845     /*
03846      * Set the interpreter's object result to an integer object w/ value 1.
03847      */
03848 
03849     Tcl_SetIntObj(Tcl_GetObjResult(interp), 1);
03850     return TCL_OK;
03851 }
03852 
03853 /*
03854  *---------------------------------------------------------------------------
03855  *
03856  * TestregexpXflags --
03857  *
03858  *      Parse a string of extended regexp flag letters, for testing.
03859  *
03860  * Results:
03861  *      No return value (you're on your own for errors here).
03862  *
03863  * Side effects:
03864  *      Modifies *cflagsPtr, a regcomp flags word, and *eflagsPtr, a
03865  *      regexec flags word, as appropriate.
03866  *
03867  *----------------------------------------------------------------------
03868  */
03869 
03870 static void
03871 TestregexpXflags(
03872     char *string,               /* The string of flags. */
03873     int length,                 /* The length of the string in bytes. */
03874     int *cflagsPtr,             /* compile flags word */
03875     int *eflagsPtr)             /* exec flags word */
03876 {
03877     int i, cflags, eflags;
03878 
03879     cflags = *cflagsPtr;
03880     eflags = *eflagsPtr;
03881     for (i = 0; i < length; i++) {
03882         switch (string[i]) {
03883         case 'a':
03884             cflags |= REG_ADVF;
03885             break;
03886         case 'b':
03887             cflags &= ~REG_ADVANCED;
03888             break;
03889         case 'c':
03890             cflags |= TCL_REG_CANMATCH;
03891             break;
03892         case 'e':
03893             cflags &= ~REG_ADVANCED;
03894             cflags |= REG_EXTENDED;
03895             break;
03896         case 'q':
03897             cflags &= ~REG_ADVANCED;
03898             cflags |= REG_QUOTE;
03899             break;
03900         case 'o':                       /* o for opaque */
03901             cflags |= REG_NOSUB;
03902             break;
03903         case 's':                       /* s for start */
03904             cflags |= REG_BOSONLY;
03905             break;
03906         case '+':
03907             cflags |= REG_FAKE;
03908             break;
03909         case ',':
03910             cflags |= REG_PROGRESS;
03911             break;
03912         case '.':
03913             cflags |= REG_DUMP;
03914             break;
03915         case ':':
03916             eflags |= REG_MTRACE;
03917             break;
03918         case ';':
03919             eflags |= REG_FTRACE;
03920             break;
03921         case '^':
03922             eflags |= REG_NOTBOL;
03923             break;
03924         case '$':
03925             eflags |= REG_NOTEOL;
03926             break;
03927         case 't':
03928             cflags |= REG_EXPECT;
03929             break;
03930         case '%':
03931             eflags |= REG_SMALL;
03932             break;
03933         }
03934     }
03935 
03936     *cflagsPtr = cflags;
03937     *eflagsPtr = eflags;
03938 }
03939 
03940 /*
03941  *----------------------------------------------------------------------
03942  *
03943  * TestreturnObjCmd --
03944  *
03945  *      This procedure implements the "testreturn" command. It is
03946  *      used to verify that a
03947  *              return TCL_RETURN;
03948  *      has same behavior as
03949  *              return Tcl_SetReturnOptions(interp, Tcl_NewObj());
03950  *
03951  * Results:
03952  *      A standard Tcl result.
03953  *
03954  * Side effects:
03955  *      See the user documentation.
03956  *
03957  *----------------------------------------------------------------------
03958  */
03959 
03960         /* ARGSUSED */
03961 static int
03962 TestreturnObjCmd(
03963     ClientData dummy,           /* Not used. */
03964     Tcl_Interp *interp,         /* Current interpreter. */
03965     int objc,                   /* Number of arguments. */
03966     Tcl_Obj *const objv[])      /* Argument objects. */
03967 {
03968     return TCL_RETURN;
03969 }
03970 
03971 /*
03972  *----------------------------------------------------------------------
03973  *
03974  * TestsetassocdataCmd --
03975  *
03976  *      This procedure implements the "testsetassocdata" command. It is used
03977  *      to test Tcl_SetAssocData.
03978  *
03979  * Results:
03980  *      A standard Tcl result.
03981  *
03982  * Side effects:
03983  *      Modifies or creates an association between a key and associated
03984  *      data for this interpreter.
03985  *
03986  *----------------------------------------------------------------------
03987  */
03988 
03989 static int
03990 TestsetassocdataCmd(
03991     ClientData clientData,      /* Not used. */
03992     Tcl_Interp *interp,         /* Current interpreter. */
03993     int argc,                   /* Number of arguments. */
03994     const char **argv)          /* Argument strings. */
03995 {
03996     char *buf, *oldData;
03997     Tcl_InterpDeleteProc *procPtr;
03998 
03999     if (argc != 3) {
04000         Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0],
04001                 " data_key data_item\"", NULL);
04002         return TCL_ERROR;
04003     }
04004 
04005     buf = ckalloc((unsigned) strlen(argv[2]) + 1);
04006     strcpy(buf, argv[2]);
04007 
04008     /*
04009      * If we previously associated a malloced value with the variable,
04010      * free it before associating a new value.
04011      */
04012 
04013     oldData = (char *) Tcl_GetAssocData(interp, argv[1], &procPtr);
04014     if ((oldData != NULL) && (procPtr == CleanupTestSetassocdataTests)) {
04015         ckfree(oldData);
04016     }
04017 
04018     Tcl_SetAssocData(interp, argv[1], CleanupTestSetassocdataTests,
04019         (ClientData) buf);
04020     return TCL_OK;
04021 }
04022 
04023 /*
04024  *----------------------------------------------------------------------
04025  *
04026  * TestsetplatformCmd --
04027  *
04028  *      This procedure implements the "testsetplatform" command. It is
04029  *      used to change the tclPlatform global variable so all file
04030  *      name conversions can be tested on a single platform.
04031  *
04032  * Results:
04033  *      A standard Tcl result.
04034  *
04035  * Side effects:
04036  *      Sets the tclPlatform global variable.
04037  *
04038  *----------------------------------------------------------------------
04039  */
04040 
04041 static int
04042 TestsetplatformCmd(
04043     ClientData clientData,      /* Not used. */
04044     Tcl_Interp *interp,         /* Current interpreter. */
04045     int argc,                   /* Number of arguments. */
04046     const char **argv)          /* Argument strings. */
04047 {
04048     size_t length;
04049     TclPlatformType *platform;
04050 
04051     platform = TclGetPlatform();
04052 
04053     if (argc != 2) {
04054         Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0],
04055                 " platform\"", NULL);
04056         return TCL_ERROR;
04057     }
04058 
04059     length = strlen(argv[1]);
04060     if (strncmp(argv[1], "unix", length) == 0) {
04061         *platform = TCL_PLATFORM_UNIX;
04062     } else if (strncmp(argv[1], "windows", length) == 0) {
04063         *platform = TCL_PLATFORM_WINDOWS;
04064     } else {
04065         Tcl_AppendResult(interp, "unsupported platform: should be one of "
04066                 "unix, or windows", NULL);
04067         return TCL_ERROR;
04068     }
04069     return TCL_OK;
04070 }
04071 
04072 /*
04073  *----------------------------------------------------------------------
04074  *
04075  * TeststaticpkgCmd --
04076  *
04077  *      This procedure implements the "teststaticpkg" command.
04078  *      It is used to test the procedure Tcl_StaticPackage.
04079  *
04080  * Results:
04081  *      A standard Tcl result.
04082  *
04083  * Side effects:
04084  *      When the packge given by argv[1] is loaded into an interpeter,
04085  *      variable "x" in that interpreter is set to "loaded".
04086  *
04087  *----------------------------------------------------------------------
04088  */
04089 
04090 static int
04091 TeststaticpkgCmd(
04092     ClientData dummy,           /* Not used. */
04093     Tcl_Interp *interp,         /* Current interpreter. */
04094     int argc,                   /* Number of arguments. */
04095     const char **argv)          /* Argument strings. */
04096 {
04097     int safe, loaded;
04098 
04099     if (argc != 4) {
04100         Tcl_AppendResult(interp, "wrong # arguments: should be \"",
04101                 argv[0], " pkgName safe loaded\"", NULL);
04102         return TCL_ERROR;
04103     }
04104     if (Tcl_GetInt(interp, argv[2], &safe) != TCL_OK) {
04105         return TCL_ERROR;
04106     }
04107     if (Tcl_GetInt(interp, argv[3], &loaded) != TCL_OK) {
04108         return TCL_ERROR;
04109     }
04110     Tcl_StaticPackage((loaded) ? interp : NULL, argv[1], StaticInitProc,
04111             (safe) ? StaticInitProc : NULL);
04112     return TCL_OK;
04113 }
04114 
04115 static int
04116 StaticInitProc(
04117     Tcl_Interp *interp)         /* Interpreter in which package is supposedly
04118                                  * being loaded. */
04119 {
04120     Tcl_SetVar(interp, "x", "loaded", TCL_GLOBAL_ONLY);
04121     return TCL_OK;
04122 }
04123 
04124 /*
04125  *----------------------------------------------------------------------
04126  *
04127  * TesttranslatefilenameCmd --
04128  *
04129  *      This procedure implements the "testtranslatefilename" command.
04130  *      It is used to test the Tcl_TranslateFileName command.
04131  *
04132  * Results:
04133  *      A standard Tcl result.
04134  *
04135  * Side effects:
04136  *      None.
04137  *
04138  *----------------------------------------------------------------------
04139  */
04140 
04141 static int
04142 TesttranslatefilenameCmd(
04143     ClientData dummy,           /* Not used. */
04144     Tcl_Interp *interp,         /* Current interpreter. */
04145     int argc,                   /* Number of arguments. */
04146     const char **argv)          /* Argument strings. */
04147 {
04148     Tcl_DString buffer;
04149     const char *result;
04150 
04151     if (argc != 2) {
04152         Tcl_AppendResult(interp, "wrong # arguments: should be \"",
04153                 argv[0], " path\"", NULL);
04154         return TCL_ERROR;
04155     }
04156     result = Tcl_TranslateFileName(interp, argv[1], &buffer);
04157     if (result == NULL) {
04158         return TCL_ERROR;
04159     }
04160     Tcl_AppendResult(interp, result, NULL);
04161     Tcl_DStringFree(&buffer);
04162     return TCL_OK;
04163 }
04164 
04165 /*
04166  *----------------------------------------------------------------------
04167  *
04168  * TestupvarCmd --
04169  *
04170  *      This procedure implements the "testupvar2" command.  It is used
04171  *      to test Tcl_UpVar and Tcl_UpVar2.
04172  *
04173  * Results:
04174  *      A standard Tcl result.
04175  *
04176  * Side effects:
04177  *      Creates or modifies an "upvar" reference.
04178  *
04179  *----------------------------------------------------------------------
04180  */
04181 
04182         /* ARGSUSED */
04183 static int
04184 TestupvarCmd(
04185     ClientData dummy,           /* Not used. */
04186     Tcl_Interp *interp,         /* Current interpreter. */
04187     int argc,                   /* Number of arguments. */
04188     const char **argv)          /* Argument strings. */
04189 {
04190     int flags = 0;
04191 
04192     if ((argc != 5) && (argc != 6)) {
04193         Tcl_AppendResult(interp, "wrong # arguments: should be \"",
04194                 argv[0], " level name ?name2? dest global\"", NULL);
04195         return TCL_ERROR;
04196     }
04197 
04198     if (argc == 5) {
04199         if (strcmp(argv[4], "global") == 0) {
04200             flags = TCL_GLOBAL_ONLY;
04201         } else if (strcmp(argv[4], "namespace") == 0) {
04202             flags = TCL_NAMESPACE_ONLY;
04203         }
04204         return Tcl_UpVar(interp, argv[1], argv[2], argv[3], flags);
04205     } else {
04206         if (strcmp(argv[5], "global") == 0) {
04207             flags = TCL_GLOBAL_ONLY;
04208         } else if (strcmp(argv[5], "namespace") == 0) {
04209             flags = TCL_NAMESPACE_ONLY;
04210         }
04211         return Tcl_UpVar2(interp, argv[1], argv[2],
04212                 (argv[3][0] == 0) ? NULL : argv[3], argv[4],
04213                 flags);
04214     }
04215 }
04216 
04217 /*
04218  *----------------------------------------------------------------------
04219  *
04220  * TestseterrorcodeCmd --
04221  *
04222  *      This procedure implements the "testseterrorcodeCmd".  This tests up to
04223  *      five elements passed to the Tcl_SetErrorCode command.
04224  *
04225  * Results:
04226  *      A standard Tcl result. Always returns TCL_ERROR so that
04227  *      the error code can be tested.
04228  *
04229  * Side effects:
04230  *      None.
04231  *
04232  *----------------------------------------------------------------------
04233  */
04234 
04235         /* ARGSUSED */
04236 static int
04237 TestseterrorcodeCmd(
04238     ClientData dummy,           /* Not used. */
04239     Tcl_Interp *interp,         /* Current interpreter. */
04240     int argc,                   /* Number of arguments. */
04241     const char **argv)          /* Argument strings. */
04242 {
04243     if (argc > 6) {
04244         Tcl_SetResult(interp, "too many args", TCL_STATIC);
04245         return TCL_ERROR;
04246     }
04247     Tcl_SetErrorCode(interp, argv[1], argv[2], argv[3], argv[4],
04248             argv[5], NULL);
04249     return TCL_ERROR;
04250 }
04251 
04252 /*
04253  *----------------------------------------------------------------------
04254  *
04255  * TestsetobjerrorcodeCmd --
04256  *
04257  *      This procedure implements the "testsetobjerrorcodeCmd".
04258  *      This tests the Tcl_SetObjErrorCode function.
04259  *
04260  * Results:
04261  *      A standard Tcl result. Always returns TCL_ERROR so that
04262  *      the error code can be tested.
04263  *
04264  * Side effects:
04265  *      None.
04266  *
04267  *----------------------------------------------------------------------
04268  */
04269 
04270         /* ARGSUSED */
04271 static int
04272 TestsetobjerrorcodeCmd(
04273     ClientData dummy,           /* Not used. */
04274     Tcl_Interp *interp,         /* Current interpreter. */
04275     int objc,                   /* Number of arguments. */
04276     Tcl_Obj *const objv[])      /* The argument objects. */
04277 {
04278     Tcl_SetObjErrorCode(interp, Tcl_ConcatObj(objc - 1, objv + 1));
04279     return TCL_ERROR;
04280 }
04281 
04282 /*
04283  *----------------------------------------------------------------------
04284  *
04285  * TestfeventCmd --
04286  *
04287  *      This procedure implements the "testfevent" command.  It is
04288  *      used for testing the "fileevent" command.
04289  *
04290  * Results:
04291  *      A standard Tcl result.
04292  *
04293  * Side effects:
04294  *      Creates and deletes interpreters.
04295  *
04296  *----------------------------------------------------------------------
04297  */
04298 
04299         /* ARGSUSED */
04300 static int
04301 TestfeventCmd(
04302     ClientData clientData,      /* Not used. */
04303     Tcl_Interp *interp,         /* Current interpreter. */
04304     int argc,                   /* Number of arguments. */
04305     const char **argv)          /* Argument strings. */
04306 {
04307     static Tcl_Interp *interp2 = NULL;
04308     int code;
04309     Tcl_Channel chan;
04310 
04311     if (argc < 2) {
04312         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
04313                 " option ?arg arg ...?", NULL);
04314         return TCL_ERROR;
04315     }
04316     if (strcmp(argv[1], "cmd") == 0) {
04317         if (argc != 3) {
04318             Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
04319                     " cmd script", NULL);
04320             return TCL_ERROR;
04321         }
04322         if (interp2 != NULL) {
04323             code = Tcl_GlobalEval(interp2, argv[2]);
04324             Tcl_SetObjResult(interp, Tcl_GetObjResult(interp2));
04325             return code;
04326         } else {
04327             Tcl_AppendResult(interp,
04328                     "called \"testfevent code\" before \"testfevent create\"",
04329                     NULL);
04330             return TCL_ERROR;
04331         }
04332     } else if (strcmp(argv[1], "create") == 0) {
04333         if (interp2 != NULL) {
04334             Tcl_DeleteInterp(interp2);
04335         }
04336         interp2 = Tcl_CreateInterp();
04337         return Tcl_Init(interp2);
04338     } else if (strcmp(argv[1], "delete") == 0) {
04339         if (interp2 != NULL) {
04340             Tcl_DeleteInterp(interp2);
04341         }
04342         interp2 = NULL;
04343     } else if (strcmp(argv[1], "share") == 0) {
04344         if (interp2 != NULL) {
04345             chan = Tcl_GetChannel(interp, argv[2], NULL);
04346             if (chan == (Tcl_Channel) NULL) {
04347                 return TCL_ERROR;
04348             }
04349             Tcl_RegisterChannel(interp2, chan);
04350         }
04351     }
04352 
04353     return TCL_OK;
04354 }
04355 
04356 /*
04357  *----------------------------------------------------------------------
04358  *
04359  * TestpanicCmd --
04360  *
04361  *      Calls the panic routine.
04362  *
04363  * Results:
04364  *      Always returns TCL_OK.
04365  *
04366  * Side effects:
04367  *      May exit application.
04368  *
04369  *----------------------------------------------------------------------
04370  */
04371 
04372 static int
04373 TestpanicCmd(
04374     ClientData dummy,           /* Not used. */
04375     Tcl_Interp *interp,         /* Current interpreter. */
04376     int argc,                   /* Number of arguments. */
04377     const char **argv)          /* Argument strings. */
04378 {
04379     const char *argString;
04380 
04381     /*
04382      *  Put the arguments into a var args structure
04383      *  Append all of the arguments together separated by spaces
04384      */
04385 
04386     argString = Tcl_Merge(argc-1, argv+1);
04387     Tcl_Panic(argString);
04388     ckfree((char *)argString);
04389 
04390     return TCL_OK;
04391 }
04392 
04393 static int
04394 TestfileCmd(
04395     ClientData dummy,           /* Not used. */
04396     Tcl_Interp *interp,         /* Current interpreter. */
04397     int argc,                   /* Number of arguments. */
04398     Tcl_Obj *const argv[])      /* The argument objects. */
04399 {
04400     int force, i, j, result;
04401     Tcl_Obj *error = NULL;
04402     char *subcmd;
04403 
04404     if (argc < 3) {
04405         return TCL_ERROR;
04406     }
04407 
04408     force = 0;
04409     i = 2;
04410     if (strcmp(Tcl_GetString(argv[2]), "-force") == 0) {
04411         force = 1;
04412         i = 3;
04413     }
04414 
04415     if (argc - i > 2) {
04416         return TCL_ERROR;
04417     }
04418 
04419     for (j = i; j < argc; j++) {
04420         if (Tcl_FSGetNormalizedPath(interp, argv[j]) == NULL) {
04421             return TCL_ERROR;
04422         }
04423     }
04424 
04425     subcmd = Tcl_GetString(argv[1]);
04426 
04427     if (strcmp(subcmd, "mv") == 0) {
04428         result = TclpObjRenameFile(argv[i], argv[i + 1]);
04429     } else if (strcmp(subcmd, "cp") == 0) {
04430         result = TclpObjCopyFile(argv[i], argv[i + 1]);
04431     } else if (strcmp(subcmd, "rm") == 0) {
04432         result = TclpObjDeleteFile(argv[i]);
04433     } else if (strcmp(subcmd, "mkdir") == 0) {
04434         result = TclpObjCreateDirectory(argv[i]);
04435     } else if (strcmp(subcmd, "cpdir") == 0) {
04436         result = TclpObjCopyDirectory(argv[i], argv[i + 1], &error);
04437     } else if (strcmp(subcmd, "rmdir") == 0) {
04438         result = TclpObjRemoveDirectory(argv[i], force, &error);
04439     } else {
04440         result = TCL_ERROR;
04441         goto end;
04442     }
04443 
04444     if (result != TCL_OK) {
04445         if (error != NULL) {
04446             if (Tcl_GetString(error)[0] != '\0') {
04447                 Tcl_AppendResult(interp, Tcl_GetString(error), " ", NULL);
04448             }
04449             Tcl_DecrRefCount(error);
04450         }
04451         Tcl_AppendResult(interp, Tcl_ErrnoId(), NULL);
04452     }
04453 
04454   end:
04455     return result;
04456 }
04457 
04458 /*
04459  *----------------------------------------------------------------------
04460  *
04461  * TestgetvarfullnameCmd --
04462  *
04463  *      Implements the "testgetvarfullname" cmd that is used when testing
04464  *      the Tcl_GetVariableFullName procedure.
04465  *
04466  * Results:
04467  *      A standard Tcl result.
04468  *
04469  * Side effects:
04470  *      None.
04471  *
04472  *----------------------------------------------------------------------
04473  */
04474 
04475 static int
04476 TestgetvarfullnameCmd(
04477     ClientData dummy,           /* Not used. */
04478     Tcl_Interp *interp,         /* Current interpreter. */
04479     int objc,                   /* Number of arguments. */
04480     Tcl_Obj *const objv[])      /* The argument objects. */
04481 {
04482     char *name, *arg;
04483     int flags = 0;
04484     Tcl_Namespace *namespacePtr;
04485     Tcl_CallFrame *framePtr;
04486     Tcl_Var variable;
04487     int result;
04488 
04489     if (objc != 3) {
04490         Tcl_WrongNumArgs(interp, 1, objv, "name scope");
04491         return TCL_ERROR;
04492     }
04493 
04494     name = Tcl_GetString(objv[1]);
04495 
04496     arg = Tcl_GetString(objv[2]);
04497     if (strcmp(arg, "global") == 0) {
04498         flags = TCL_GLOBAL_ONLY;
04499     } else if (strcmp(arg, "namespace") == 0) {
04500         flags = TCL_NAMESPACE_ONLY;
04501     }
04502 
04503     /*
04504      * This command, like any other created with Tcl_Create[Obj]Command, runs
04505      * in the global namespace. As a "namespace-aware" command that needs to
04506      * run in a particular namespace, it must activate that namespace itself.
04507      */
04508 
04509     if (flags == TCL_NAMESPACE_ONLY) {
04510         namespacePtr = Tcl_FindNamespace(interp, "::test_ns_var", NULL,
04511                 TCL_LEAVE_ERR_MSG);
04512         if (namespacePtr == NULL) {
04513             return TCL_ERROR;
04514         }
04515         result = TclPushStackFrame(interp, &framePtr, namespacePtr,
04516                 /*isProcCallFrame*/ 0);
04517         if (result != TCL_OK) {
04518             return result;
04519         }
04520     }
04521 
04522     variable = Tcl_FindNamespaceVar(interp, name, NULL,
04523             (flags | TCL_LEAVE_ERR_MSG));
04524 
04525     if (flags == TCL_NAMESPACE_ONLY) {
04526         TclPopStackFrame(interp);
04527     }
04528     if (variable == (Tcl_Var) NULL) {
04529         return TCL_ERROR;
04530     }
04531     Tcl_GetVariableFullName(interp, variable, Tcl_GetObjResult(interp));
04532     return TCL_OK;
04533 }
04534 
04535 /*
04536  *----------------------------------------------------------------------
04537  *
04538  * GetTimesCmd --
04539  *
04540  *      This procedure implements the "gettimes" command.  It is used for
04541  *      computing the time needed for various basic operations such as reading
04542  *      variables, allocating memory, sprintf, converting variables, etc.
04543  *
04544  * Results:
04545  *      A standard Tcl result.
04546  *
04547  * Side effects:
04548  *      Allocates and frees memory, sets a variable "a" in the interpreter.
04549  *
04550  *----------------------------------------------------------------------
04551  */
04552 
04553 static int
04554 GetTimesCmd(
04555     ClientData unused,          /* Unused. */
04556     Tcl_Interp *interp,         /* The current interpreter. */
04557     int argc,                   /* The number of arguments. */
04558     const char **argv)          /* The argument strings. */
04559 {
04560     Interp *iPtr = (Interp *) interp;
04561     int i, n;
04562     double timePer;
04563     Tcl_Time start, stop;
04564     Tcl_Obj *objPtr, **objv;
04565     const char *s;
04566     char newString[TCL_INTEGER_SPACE];
04567 
04568     /* alloc & free 100000 times */
04569     fprintf(stderr, "alloc & free 100000 6 word items\n");
04570     Tcl_GetTime(&start);
04571     for (i = 0;  i < 100000;  i++) {
04572         objPtr = (Tcl_Obj *) ckalloc(sizeof(Tcl_Obj));
04573         ckfree((char *) objPtr);
04574     }
04575     Tcl_GetTime(&stop);
04576     timePer = (stop.sec - start.sec)*1000000 + (stop.usec - start.usec);
04577     fprintf(stderr, "   %.3f usec per alloc+free\n", timePer/100000);
04578 
04579     /* alloc 5000 times */
04580     fprintf(stderr, "alloc 5000 6 word items\n");
04581     objv = (Tcl_Obj **) ckalloc(5000 * sizeof(Tcl_Obj *));
04582     Tcl_GetTime(&start);
04583     for (i = 0;  i < 5000;  i++) {
04584         objv[i] = (Tcl_Obj *) ckalloc(sizeof(Tcl_Obj));
04585     }
04586     Tcl_GetTime(&stop);
04587     timePer = (stop.sec - start.sec)*1000000 + (stop.usec - start.usec);
04588     fprintf(stderr, "   %.3f usec per alloc\n", timePer/5000);
04589 
04590     /* free 5000 times */
04591     fprintf(stderr, "free 5000 6 word items\n");
04592     Tcl_GetTime(&start);
04593     for (i = 0;  i < 5000;  i++) {
04594         ckfree((char *) objv[i]);
04595     }
04596     Tcl_GetTime(&stop);
04597     timePer = (stop.sec - start.sec)*1000000 + (stop.usec - start.usec);
04598     fprintf(stderr, "   %.3f usec per free\n", timePer/5000);
04599 
04600     /* Tcl_NewObj 5000 times */
04601     fprintf(stderr, "Tcl_NewObj 5000 times\n");
04602     Tcl_GetTime(&start);
04603     for (i = 0;  i < 5000;  i++) {
04604         objv[i] = Tcl_NewObj();
04605     }
04606     Tcl_GetTime(&stop);
04607     timePer = (stop.sec - start.sec)*1000000 + (stop.usec - start.usec);
04608     fprintf(stderr, "   %.3f usec per Tcl_NewObj\n", timePer/5000);
04609 
04610     /* Tcl_DecrRefCount 5000 times */
04611     fprintf(stderr, "Tcl_DecrRefCount 5000 times\n");
04612     Tcl_GetTime(&start);
04613     for (i = 0;  i < 5000;  i++) {
04614         objPtr = objv[i];
04615         Tcl_DecrRefCount(objPtr);
04616     }
04617     Tcl_GetTime(&stop);
04618     timePer = (stop.sec - start.sec)*1000000 + (stop.usec - start.usec);
04619     fprintf(stderr, "   %.3f usec per Tcl_DecrRefCount\n", timePer/5000);
04620     ckfree((char *) objv);
04621 
04622     /* TclGetString 100000 times */
04623     fprintf(stderr, "TclGetStringFromObj of \"12345\" 100000 times\n");
04624     objPtr = Tcl_NewStringObj("12345", -1);
04625     Tcl_GetTime(&start);
04626     for (i = 0;  i < 100000;  i++) {
04627         (void) TclGetString(objPtr);
04628     }
04629     Tcl_GetTime(&stop);
04630     timePer = (stop.sec - start.sec)*1000000 + (stop.usec - start.usec);
04631     fprintf(stderr, "   %.3f usec per TclGetStringFromObj of \"12345\"\n",
04632             timePer/100000);
04633 
04634     /* Tcl_GetIntFromObj 100000 times */
04635     fprintf(stderr, "Tcl_GetIntFromObj of \"12345\" 100000 times\n");
04636     Tcl_GetTime(&start);
04637     for (i = 0;  i < 100000;  i++) {
04638         if (Tcl_GetIntFromObj(interp, objPtr, &n) != TCL_OK) {
04639             return TCL_ERROR;
04640         }
04641     }
04642     Tcl_GetTime(&stop);
04643     timePer = (stop.sec - start.sec)*1000000 + (stop.usec - start.usec);
04644     fprintf(stderr, "   %.3f usec per Tcl_GetIntFromObj of \"12345\"\n",
04645             timePer/100000);
04646     Tcl_DecrRefCount(objPtr);
04647 
04648     /* Tcl_GetInt 100000 times */
04649     fprintf(stderr, "Tcl_GetInt of \"12345\" 100000 times\n");
04650     Tcl_GetTime(&start);
04651     for (i = 0;  i < 100000;  i++) {
04652         if (Tcl_GetInt(interp, "12345", &n) != TCL_OK) {
04653             return TCL_ERROR;
04654         }
04655     }
04656     Tcl_GetTime(&stop);
04657     timePer = (stop.sec - start.sec)*1000000 + (stop.usec - start.usec);
04658     fprintf(stderr, "   %.3f usec per Tcl_GetInt of \"12345\"\n",
04659             timePer/100000);
04660 
04661     /* sprintf 100000 times */
04662     fprintf(stderr, "sprintf of 12345 100000 times\n");
04663     Tcl_GetTime(&start);
04664     for (i = 0;  i < 100000;  i++) {
04665         sprintf(newString, "%d", 12345);
04666     }
04667     Tcl_GetTime(&stop);
04668     timePer = (stop.sec - start.sec)*1000000 + (stop.usec - start.usec);
04669     fprintf(stderr, "   %.3f usec per sprintf of 12345\n",
04670             timePer/100000);
04671 
04672     /* hashtable lookup 100000 times */
04673     fprintf(stderr, "hashtable lookup of \"gettimes\" 100000 times\n");
04674     Tcl_GetTime(&start);
04675     for (i = 0;  i < 100000;  i++) {
04676         (void) Tcl_FindHashEntry(&iPtr->globalNsPtr->cmdTable, "gettimes");
04677     }
04678     Tcl_GetTime(&stop);
04679     timePer = (stop.sec - start.sec)*1000000 + (stop.usec - start.usec);
04680     fprintf(stderr, "   %.3f usec per hashtable lookup of \"gettimes\"\n",
04681             timePer/100000);
04682 
04683     /* Tcl_SetVar 100000 times */
04684     fprintf(stderr, "Tcl_SetVar of \"12345\" 100000 times\n");
04685     Tcl_GetTime(&start);
04686     for (i = 0;  i < 100000;  i++) {
04687         s = Tcl_SetVar(interp, "a", "12345", TCL_LEAVE_ERR_MSG);
04688         if (s == NULL) {
04689             return TCL_ERROR;
04690         }
04691     }
04692     Tcl_GetTime(&stop);
04693     timePer = (stop.sec - start.sec)*1000000 + (stop.usec - start.usec);
04694     fprintf(stderr, "   %.3f usec per Tcl_SetVar of a to \"12345\"\n",
04695             timePer/100000);
04696 
04697     /* Tcl_GetVar 100000 times */
04698     fprintf(stderr, "Tcl_GetVar of a==\"12345\" 100000 times\n");
04699     Tcl_GetTime(&start);
04700     for (i = 0;  i < 100000;  i++) {
04701         s = Tcl_GetVar(interp, "a", TCL_LEAVE_ERR_MSG);
04702         if (s == NULL) {
04703             return TCL_ERROR;
04704         }
04705     }
04706     Tcl_GetTime(&stop);
04707     timePer = (stop.sec - start.sec)*1000000 + (stop.usec - start.usec);
04708     fprintf(stderr, "   %.3f usec per Tcl_GetVar of a==\"12345\"\n",
04709             timePer/100000);
04710 
04711     Tcl_ResetResult(interp);
04712     return TCL_OK;
04713 }
04714 
04715 /*
04716  *----------------------------------------------------------------------
04717  *
04718  * NoopCmd --
04719  *
04720  *      This procedure is just used to time the overhead involved in
04721  *      parsing and invoking a command.
04722  *
04723  * Results:
04724  *      None.
04725  *
04726  * Side effects:
04727  *      None.
04728  *
04729  *----------------------------------------------------------------------
04730  */
04731 
04732 static int
04733 NoopCmd(
04734     ClientData unused,          /* Unused. */
04735     Tcl_Interp *interp,         /* The current interpreter. */
04736     int argc,                   /* The number of arguments. */
04737     const char **argv)          /* The argument strings. */
04738 {
04739     return TCL_OK;
04740 }
04741 
04742 /*
04743  *----------------------------------------------------------------------
04744  *
04745  * NoopObjCmd --
04746  *
04747  *      This object-based procedure is just used to time the overhead
04748  *      involved in parsing and invoking a command.
04749  *
04750  * Results:
04751  *      Returns the TCL_OK result code.
04752  *
04753  * Side effects:
04754  *      None.
04755  *
04756  *----------------------------------------------------------------------
04757  */
04758 
04759 static int
04760 NoopObjCmd(
04761     ClientData unused,          /* Not used. */
04762     Tcl_Interp *interp,         /* Current interpreter. */
04763     int objc,                   /* Number of arguments. */
04764     Tcl_Obj *const objv[])      /* The argument objects. */
04765 {
04766     return TCL_OK;
04767 }
04768 
04769 /*
04770  *----------------------------------------------------------------------
04771  *
04772  * TestsetCmd --
04773  *
04774  *      Implements the "testset{err,noerr}" cmds that are used when testing
04775  *      Tcl_Set/GetVar C Api with/without TCL_LEAVE_ERR_MSG flag
04776  *
04777  * Results:
04778  *      A standard Tcl result.
04779  *
04780  * Side effects:
04781  *     Variables may be set.
04782  *
04783  *----------------------------------------------------------------------
04784  */
04785 
04786         /* ARGSUSED */
04787 static int
04788 TestsetCmd(
04789     ClientData data,            /* Additional flags for Get/SetVar2. */
04790     register Tcl_Interp *interp,/* Current interpreter. */
04791     int argc,                   /* Number of arguments. */
04792     const char **argv)          /* Argument strings. */
04793 {
04794     int flags = PTR2INT(data);
04795     const char *value;
04796 
04797     if (argc == 2) {
04798         Tcl_SetResult(interp, "before get", TCL_STATIC);
04799         value = Tcl_GetVar2(interp, argv[1], NULL, flags);
04800         if (value == NULL) {
04801             return TCL_ERROR;
04802         }
04803         Tcl_AppendElement(interp, value);
04804         return TCL_OK;
04805     } else if (argc == 3) {
04806         Tcl_SetResult(interp, "before set", TCL_STATIC);
04807         value = Tcl_SetVar2(interp, argv[1], NULL, argv[2], flags);
04808         if (value == NULL) {
04809             return TCL_ERROR;
04810         }
04811         Tcl_AppendElement(interp, value);
04812         return TCL_OK;
04813     } else {
04814         Tcl_AppendResult(interp, "wrong # args: should be \"",
04815                 argv[0], " varName ?newValue?\"", NULL);
04816         return TCL_ERROR;
04817     }
04818 }
04819 static int
04820 Testset2Cmd(
04821     ClientData data,            /* Additional flags for Get/SetVar2. */
04822     register Tcl_Interp *interp,/* Current interpreter. */
04823     int argc,                   /* Number of arguments. */
04824     const char **argv)          /* Argument strings. */
04825 {
04826     int flags = PTR2INT(data);
04827     const char *value;
04828 
04829     if (argc == 3) {
04830         Tcl_SetResult(interp, "before get", TCL_STATIC);
04831         value = Tcl_GetVar2(interp, argv[1], argv[2], flags);
04832         if (value == NULL) {
04833             return TCL_ERROR;
04834         }
04835         Tcl_AppendElement(interp, value);
04836         return TCL_OK;
04837     } else if (argc == 4) {
04838         Tcl_SetResult(interp, "before set", TCL_STATIC);
04839         value = Tcl_SetVar2(interp, argv[1], argv[2], argv[3], flags);
04840         if (value == NULL) {
04841             return TCL_ERROR;
04842         }
04843         Tcl_AppendElement(interp, value);
04844         return TCL_OK;
04845     } else {
04846         Tcl_AppendResult(interp, "wrong # args: should be \"",
04847                 argv[0], " varName elemName ?newValue?\"", NULL);
04848         return TCL_ERROR;
04849     }
04850 }
04851 
04852 /*
04853  *----------------------------------------------------------------------
04854  *
04855  * TestsaveresultCmd --
04856  *
04857  *      Implements the "testsaveresult" cmd that is used when testing the
04858  *      Tcl_SaveResult, Tcl_RestoreResult, and Tcl_DiscardResult interfaces.
04859  *
04860  * Results:
04861  *      A standard Tcl result.
04862  *
04863  * Side effects:
04864  *      None.
04865  *
04866  *----------------------------------------------------------------------
04867  */
04868 
04869         /* ARGSUSED */
04870 static int
04871 TestsaveresultCmd(
04872     ClientData dummy,           /* Not used. */
04873     register Tcl_Interp *interp,/* Current interpreter. */
04874     int objc,                   /* Number of arguments. */
04875     Tcl_Obj *const objv[])      /* The argument objects. */
04876 {
04877     int discard, result, index;
04878     Tcl_SavedResult state;
04879     Tcl_Obj *objPtr;
04880     static const char *optionStrings[] = {
04881         "append", "dynamic", "free", "object", "small", NULL
04882     };
04883     enum options {
04884         RESULT_APPEND, RESULT_DYNAMIC, RESULT_FREE, RESULT_OBJECT, RESULT_SMALL
04885     };
04886 
04887     /*
04888      * Parse arguments
04889      */
04890 
04891     if (objc != 4) {
04892         Tcl_WrongNumArgs(interp, 1, objv, "type script discard");
04893         return TCL_ERROR;
04894     }
04895     if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0,
04896             &index) != TCL_OK) {
04897         return TCL_ERROR;
04898     }
04899     if (Tcl_GetBooleanFromObj(interp, objv[3], &discard) != TCL_OK) {
04900         return TCL_ERROR;
04901     }
04902 
04903     objPtr = NULL;              /* Lint. */
04904     switch ((enum options) index) {
04905     case RESULT_SMALL:
04906         Tcl_SetResult(interp, "small result", TCL_VOLATILE);
04907         break;
04908     case RESULT_APPEND:
04909         Tcl_AppendResult(interp, "append result", NULL);
04910         break;
04911     case RESULT_FREE: {
04912         char *buf = ckalloc(200);
04913 
04914         strcpy(buf, "free result");
04915         Tcl_SetResult(interp, buf, TCL_DYNAMIC);
04916         break;
04917     }
04918     case RESULT_DYNAMIC:
04919         Tcl_SetResult(interp, "dynamic result", TestsaveresultFree);
04920         break;
04921     case RESULT_OBJECT:
04922         objPtr = Tcl_NewStringObj("object result", -1);
04923         Tcl_SetObjResult(interp, objPtr);
04924         break;
04925     }
04926 
04927     freeCount = 0;
04928     Tcl_SaveResult(interp, &state);
04929 
04930     if (((enum options) index) == RESULT_OBJECT) {
04931         result = Tcl_EvalObjEx(interp, objv[2], 0);
04932     } else {
04933         result = Tcl_Eval(interp, Tcl_GetString(objv[2]));
04934     }
04935 
04936     if (discard) {
04937         Tcl_DiscardResult(&state);
04938     } else {
04939         Tcl_RestoreResult(interp, &state);
04940         result = TCL_OK;
04941     }
04942 
04943     switch ((enum options) index) {
04944     case RESULT_DYNAMIC: {
04945         int present = interp->freeProc == TestsaveresultFree;
04946         int called = freeCount;
04947 
04948         Tcl_AppendElement(interp, called ? "called" : "notCalled");
04949         Tcl_AppendElement(interp, present ? "present" : "missing");
04950         break;
04951     }
04952     case RESULT_OBJECT:
04953         Tcl_AppendElement(interp, Tcl_GetObjResult(interp) == objPtr
04954                 ? "same" : "different");
04955         break;
04956     default:
04957         break;
04958     }
04959     return result;
04960 }
04961 
04962 /*
04963  *----------------------------------------------------------------------
04964  *
04965  * TestsaveresultFree --
04966  *
04967  *      Special purpose freeProc used by TestsaveresultCmd.
04968  *
04969  * Results:
04970  *      None.
04971  *
04972  * Side effects:
04973  *      Increments the freeCount.
04974  *
04975  *----------------------------------------------------------------------
04976  */
04977 
04978 static void
04979 TestsaveresultFree(
04980     char *blockPtr)
04981 {
04982     freeCount++;
04983 }
04984 #ifdef USE_OBSOLETE_FS_HOOKS
04985 
04986 /*
04987  *----------------------------------------------------------------------
04988  *
04989  * TeststatprocCmd  --
04990  *
04991  *      Implements the "testTclStatProc" cmd that is used to test the
04992  *      'TclStatInsertProc' & 'TclStatDeleteProc' C Apis.
04993  *
04994  * Results:
04995  *      A standard Tcl result.
04996  *
04997  * Side effects:
04998  *      None.
04999  *
05000  *----------------------------------------------------------------------
05001  */
05002 
05003 static int
05004 TeststatprocCmd(
05005     ClientData dummy,           /* Not used. */
05006     register Tcl_Interp *interp,/* Current interpreter. */
05007     int argc,                   /* Number of arguments. */
05008     const char **argv)          /* Argument strings. */
05009 {
05010     TclStatProc_ *proc;
05011     int retVal;
05012 
05013     if (argc != 3) {
05014         Tcl_AppendResult(interp, "wrong # args: should be \"",
05015                 argv[0], " option arg\"", NULL);
05016         return TCL_ERROR;
05017     }
05018 
05019     if (strcmp(argv[2], "TclpStat") == 0) {
05020         proc = PretendTclpStat;
05021     } else if (strcmp(argv[2], "TestStatProc1") == 0) {
05022         proc = TestStatProc1;
05023     } else if (strcmp(argv[2], "TestStatProc2") == 0) {
05024         proc = TestStatProc2;
05025     } else if (strcmp(argv[2], "TestStatProc3") == 0) {
05026         proc = TestStatProc3;
05027     } else {
05028         Tcl_AppendResult(interp, "bad arg \"", argv[1], "\": "
05029                 "must be TclpStat, "
05030                 "TestStatProc1, TestStatProc2, or TestStatProc3", NULL);
05031         return TCL_ERROR;
05032     }
05033 
05034     if (strcmp(argv[1], "insert") == 0) {
05035         if (proc == PretendTclpStat) {
05036             Tcl_AppendResult(interp, "bad arg \"", argv[1], "\": "
05037                    "must be "
05038                    "TestStatProc1, TestStatProc2, or TestStatProc3", NULL);
05039             return TCL_ERROR;
05040         }
05041         retVal = TclStatInsertProc(proc);
05042     } else if (strcmp(argv[1], "delete") == 0) {
05043         retVal = TclStatDeleteProc(proc);
05044     } else {
05045         Tcl_AppendResult(interp, "bad option \"", argv[1], "\": "
05046                 "must be insert or delete", NULL);
05047         return TCL_ERROR;
05048     }
05049 
05050     if (retVal == TCL_ERROR) {
05051         Tcl_AppendResult(interp, "\"", argv[2], "\": "
05052                 "could not be ", argv[1], "ed", NULL);
05053     }
05054 
05055     return retVal;
05056 }
05057 
05058 static int
05059 PretendTclpStat(
05060     const char *path,
05061     struct stat *buf)
05062 {
05063     int ret;
05064     Tcl_Obj *pathPtr = Tcl_NewStringObj(path, -1);
05065 #ifdef TCL_WIDE_INT_IS_LONG
05066     Tcl_IncrRefCount(pathPtr);
05067     ret = TclpObjStat(pathPtr, buf);
05068     Tcl_DecrRefCount(pathPtr);
05069     return ret;
05070 #else /* TCL_WIDE_INT_IS_LONG */
05071     Tcl_StatBuf realBuf;
05072     Tcl_IncrRefCount(pathPtr);
05073     ret = TclpObjStat(pathPtr, &realBuf);
05074     Tcl_DecrRefCount(pathPtr);
05075     if (ret != -1) {
05076 #   define OUT_OF_RANGE(x) \
05077         (((Tcl_WideInt)(x)) < Tcl_LongAsWide(LONG_MIN) || \
05078          ((Tcl_WideInt)(x)) > Tcl_LongAsWide(LONG_MAX))
05079 #if defined(__GNUC__) && __GNUC__ >= 2
05080 /*
05081  * Workaround gcc warning of "comparison is always false due to limited range of
05082  * data type" in this macro by checking max type size, and when necessary ANDing
05083  * with the complement of ULONG_MAX instead of the comparison:
05084  */
05085 #   define OUT_OF_URANGE(x) \
05086         ((((Tcl_WideUInt)(~ (__typeof__(x)) 0)) > (Tcl_WideUInt)ULONG_MAX) && \
05087          (((Tcl_WideUInt)(x)) & ~(Tcl_WideUInt)ULONG_MAX))
05088 #else
05089 #   define OUT_OF_URANGE(x) \
05090         (((Tcl_WideUInt)(x)) > (Tcl_WideUInt)ULONG_MAX)
05091 #endif
05092 
05093         /*
05094          * Perform the result-buffer overflow check manually.
05095          *
05096          * Note that ino_t/ino64_t is unsigned...
05097          */
05098 
05099         if (OUT_OF_URANGE(realBuf.st_ino) || OUT_OF_RANGE(realBuf.st_size)
05100 #   ifdef HAVE_ST_BLOCKS
05101                 || OUT_OF_RANGE(realBuf.st_blocks)
05102 #   endif
05103             ) {
05104 #   ifdef EOVERFLOW
05105             errno = EOVERFLOW;
05106 #   else
05107 #       ifdef EFBIG
05108             errno = EFBIG;
05109 #       else
05110 #           error "what error should be returned for a value out of range?"
05111 #       endif
05112 #   endif
05113             return -1;
05114         }
05115 
05116 #   undef OUT_OF_RANGE
05117 #   undef OUT_OF_URANGE
05118 
05119         /*
05120          * Copy across all supported fields, with possible type coercions on
05121          * those fields that change between the normal and lf64 versions of
05122          * the stat structure (on Solaris at least.) This is slow when the
05123          * structure sizes coincide, but that's what you get for mixing
05124          * interfaces...
05125          */
05126 
05127         buf->st_mode    = realBuf.st_mode;
05128         buf->st_ino     = (ino_t) realBuf.st_ino;
05129         buf->st_dev     = realBuf.st_dev;
05130         buf->st_rdev    = realBuf.st_rdev;
05131         buf->st_nlink   = realBuf.st_nlink;
05132         buf->st_uid     = realBuf.st_uid;
05133         buf->st_gid     = realBuf.st_gid;
05134         buf->st_size    = (off_t) realBuf.st_size;
05135         buf->st_atime   = realBuf.st_atime;
05136         buf->st_mtime   = realBuf.st_mtime;
05137         buf->st_ctime   = realBuf.st_ctime;
05138 #   ifdef HAVE_ST_BLOCKS
05139         buf->st_blksize = realBuf.st_blksize;
05140         buf->st_blocks  = (blkcnt_t) realBuf.st_blocks;
05141 #   endif
05142     }
05143     return ret;
05144 #endif /* TCL_WIDE_INT_IS_LONG */
05145 }
05146 
05147 static int
05148 TestStatProc1(
05149     const char *path,
05150     struct stat *buf)
05151 {
05152     memset(buf, 0, sizeof(struct stat));
05153     buf->st_size = 1234;
05154     return ((strstr(path, "testStat1%.fil") == NULL) ? -1 : 0);
05155 }
05156 
05157 static int
05158 TestStatProc2(
05159     const char *path,
05160     struct stat *buf)
05161 {
05162     memset(buf, 0, sizeof(struct stat));
05163     buf->st_size = 2345;
05164     return ((strstr(path, "testStat2%.fil") == NULL) ? -1 : 0);
05165 }
05166 
05167 static int
05168 TestStatProc3(
05169     const char *path,
05170     struct stat *buf)
05171 {
05172     memset(buf, 0, sizeof(struct stat));
05173     buf->st_size = 3456;
05174     return ((strstr(path, "testStat3%.fil") == NULL) ? -1 : 0);
05175 }
05176 #endif
05177 
05178 /*
05179  *----------------------------------------------------------------------
05180  *
05181  * TestmainthreadCmd  --
05182  *
05183  *      Implements the "testmainthread" cmd that is used to test the
05184  *      'Tcl_GetCurrentThread' API.
05185  *
05186  * Results:
05187  *      A standard Tcl result.
05188  *
05189  * Side effects:
05190  *      None.
05191  *
05192  *----------------------------------------------------------------------
05193  */
05194 
05195 static int
05196 TestmainthreadCmd(
05197     ClientData dummy,           /* Not used. */
05198     register Tcl_Interp *interp,/* Current interpreter. */
05199     int argc,                   /* Number of arguments. */
05200     const char **argv)          /* Argument strings. */
05201 {
05202   if (argc == 1) {
05203       Tcl_Obj *idObj = Tcl_NewLongObj((long)Tcl_GetCurrentThread());
05204       Tcl_SetObjResult(interp, idObj);
05205       return TCL_OK;
05206   } else {
05207       Tcl_SetResult(interp, "wrong # args", TCL_STATIC);
05208       return TCL_ERROR;
05209   }
05210 }
05211 
05212 /*
05213  *----------------------------------------------------------------------
05214  *
05215  * MainLoop --
05216  *
05217  *      A main loop set by TestsetmainloopCmd below.
05218  *
05219  * Results:
05220  *      None.
05221  *
05222  * Side effects:
05223  *      Event handlers could do anything.
05224  *
05225  *----------------------------------------------------------------------
05226  */
05227 
05228 static void
05229 MainLoop(void)
05230 {
05231     while (!exitMainLoop) {
05232         Tcl_DoOneEvent(0);
05233     }
05234     fprintf(stdout,"Exit MainLoop\n");
05235     fflush(stdout);
05236 }
05237 
05238 /*
05239  *----------------------------------------------------------------------
05240  *
05241  * TestsetmainloopCmd  --
05242  *
05243  *      Implements the "testsetmainloop" cmd that is used to test the
05244  *      'Tcl_SetMainLoop' API.
05245  *
05246  * Results:
05247  *      A standard Tcl result.
05248  *
05249  * Side effects:
05250  *      None.
05251  *
05252  *----------------------------------------------------------------------
05253  */
05254 
05255 static int
05256 TestsetmainloopCmd(
05257     ClientData dummy,           /* Not used. */
05258     register Tcl_Interp *interp,/* Current interpreter. */
05259     int argc,                   /* Number of arguments. */
05260     const char **argv)          /* Argument strings. */
05261 {
05262   exitMainLoop = 0;
05263   Tcl_SetMainLoop(MainLoop);
05264   return TCL_OK;
05265 }
05266 
05267 /*
05268  *----------------------------------------------------------------------
05269  *
05270  * TestexitmainloopCmd  --
05271  *
05272  *      Implements the "testexitmainloop" cmd that is used to test the
05273  *      'Tcl_SetMainLoop' API.
05274  *
05275  * Results:
05276  *      A standard Tcl result.
05277  *
05278  * Side effects:
05279  *      None.
05280  *
05281  *----------------------------------------------------------------------
05282  */
05283 
05284 static int
05285 TestexitmainloopCmd(
05286     ClientData dummy,           /* Not used. */
05287     register Tcl_Interp *interp,/* Current interpreter. */
05288     int argc,                   /* Number of arguments. */
05289     const char **argv)          /* Argument strings. */
05290 {
05291   exitMainLoop = 1;
05292   return TCL_OK;
05293 }
05294 #ifdef USE_OBSOLETE_FS_HOOKS
05295 
05296 /*
05297  *----------------------------------------------------------------------
05298  *
05299  * TestaccessprocCmd  --
05300  *
05301  *      Implements the "testTclAccessProc" cmd that is used to test the
05302  *      'TclAccessInsertProc' & 'TclAccessDeleteProc' C Apis.
05303  *
05304  * Results:
05305  *      A standard Tcl result.
05306  *
05307  * Side effects:
05308  *      None.
05309  *
05310  *----------------------------------------------------------------------
05311  */
05312 
05313 static int
05314 TestaccessprocCmd(
05315     ClientData dummy,           /* Not used. */
05316     register Tcl_Interp *interp,/* Current interpreter. */
05317     int argc,                   /* Number of arguments. */
05318     const char **argv)          /* Argument strings. */
05319 {
05320     TclAccessProc_ *proc;
05321     int retVal;
05322 
05323     if (argc != 3) {
05324         Tcl_AppendResult(interp, "wrong # args: should be \"",
05325                 argv[0], " option arg\"", NULL);
05326         return TCL_ERROR;
05327     }
05328 
05329     if (strcmp(argv[2], "TclpAccess") == 0) {
05330         proc = PretendTclpAccess;
05331     } else if (strcmp(argv[2], "TestAccessProc1") == 0) {
05332         proc = TestAccessProc1;
05333     } else if (strcmp(argv[2], "TestAccessProc2") == 0) {
05334         proc = TestAccessProc2;
05335     } else if (strcmp(argv[2], "TestAccessProc3") == 0) {
05336         proc = TestAccessProc3;
05337     } else {
05338         Tcl_AppendResult(interp, "bad arg \"", argv[1], "\": "
05339                 "must be TclpAccess, "
05340                 "TestAccessProc1, TestAccessProc2, or TestAccessProc3", NULL);
05341         return TCL_ERROR;
05342     }
05343 
05344     if (strcmp(argv[1], "insert") == 0) {
05345         if (proc == PretendTclpAccess) {
05346             Tcl_AppendResult(interp, "bad arg \"", argv[1], "\": must be "
05347                    "TestAccessProc1, TestAccessProc2, or TestAccessProc3"
05348                    NULL);
05349             return TCL_ERROR;
05350         }
05351         retVal = TclAccessInsertProc(proc);
05352     } else if (strcmp(argv[1], "delete") == 0) {
05353         retVal = TclAccessDeleteProc(proc);
05354     } else {
05355         Tcl_AppendResult(interp, "bad option \"", argv[1], "\": "
05356                 "must be insert or delete", NULL);
05357         return TCL_ERROR;
05358     }
05359 
05360     if (retVal == TCL_ERROR) {
05361         Tcl_AppendResult(interp, "\"", argv[2], "\": "
05362                 "could not be ", argv[1], "ed", NULL);
05363     }
05364 
05365     return retVal;
05366 }
05367 
05368 static int
05369 PretendTclpAccess(
05370     const char *path,
05371     int mode)
05372 {
05373     int ret;
05374     Tcl_Obj *pathPtr = Tcl_NewStringObj(path, -1);
05375     Tcl_IncrRefCount(pathPtr);
05376     ret = TclpObjAccess(pathPtr, mode);
05377     Tcl_DecrRefCount(pathPtr);
05378     return ret;
05379 }
05380 
05381 static int
05382 TestAccessProc1(
05383     const char *path,
05384     int mode)
05385 {
05386     return ((strstr(path, "testAccess1%.fil") == NULL) ? -1 : 0);
05387 }
05388 
05389 static int
05390 TestAccessProc2(
05391     const char *path,
05392     int mode)
05393 {
05394     return ((strstr(path, "testAccess2%.fil") == NULL) ? -1 : 0);
05395 }
05396 
05397 static int
05398 TestAccessProc3(
05399     const char *path,
05400     int mode)
05401 {
05402     return ((strstr(path, "testAccess3%.fil") == NULL) ? -1 : 0);
05403 }
05404 
05405 /*
05406  *----------------------------------------------------------------------
05407  *
05408  * TestopenfilechannelprocCmd  --
05409  *
05410  *      Implements the "testTclOpenFileChannelProc" cmd that is used to test
05411  *      the 'TclOpenFileChannelInsertProc' & 'TclOpenFileChannelDeleteProc' C
05412  *      Apis.
05413  *
05414  * Results:
05415  *      A standard Tcl result.
05416  *
05417  * Side effects:
05418  *      None.
05419  *
05420  *----------------------------------------------------------------------
05421  */
05422 
05423 static int
05424 TestopenfilechannelprocCmd(
05425     ClientData dummy,           /* Not used. */
05426     register Tcl_Interp *interp,/* Current interpreter. */
05427     int argc,                   /* Number of arguments. */
05428     const char **argv)          /* Argument strings. */
05429 {
05430     TclOpenFileChannelProc_ *proc;
05431     int retVal;
05432 
05433     if (argc != 3) {
05434         Tcl_AppendResult(interp, "wrong # args: should be \"",
05435                 argv[0], " option arg\"", NULL);
05436         return TCL_ERROR;
05437     }
05438 
05439     if (strcmp(argv[2], "TclpOpenFileChannel") == 0) {
05440         proc = PretendTclpOpenFileChannel;
05441     } else if (strcmp(argv[2], "TestOpenFileChannelProc1") == 0) {
05442         proc = TestOpenFileChannelProc1;
05443     } else if (strcmp(argv[2], "TestOpenFileChannelProc2") == 0) {
05444         proc = TestOpenFileChannelProc2;
05445     } else if (strcmp(argv[2], "TestOpenFileChannelProc3") == 0) {
05446         proc = TestOpenFileChannelProc3;
05447     } else {
05448         Tcl_AppendResult(interp, "bad arg \"", argv[1], "\": "
05449                 "must be TclpOpenFileChannel, "
05450                 "TestOpenFileChannelProc1, TestOpenFileChannelProc2, or "
05451                 "TestOpenFileChannelProc3", NULL);
05452         return TCL_ERROR;
05453     }
05454 
05455     if (strcmp(argv[1], "insert") == 0) {
05456         if (proc == PretendTclpOpenFileChannel) {
05457             Tcl_AppendResult(interp, "bad arg \"", argv[1], "\": "
05458                    "must be "
05459                    "TestOpenFileChannelProc1, TestOpenFileChannelProc2, or "
05460                    "TestOpenFileChannelProc3", NULL);
05461             return TCL_ERROR;
05462         }
05463         retVal = TclOpenFileChannelInsertProc(proc);
05464     } else if (strcmp(argv[1], "delete") == 0) {
05465         retVal = TclOpenFileChannelDeleteProc(proc);
05466     } else {
05467         Tcl_AppendResult(interp, "bad option \"", argv[1], "\": "
05468                 "must be insert or delete", NULL);
05469         return TCL_ERROR;
05470     }
05471 
05472     if (retVal == TCL_ERROR) {
05473         Tcl_AppendResult(interp, "\"", argv[2], "\": "
05474                 "could not be ", argv[1], "ed", NULL);
05475     }
05476 
05477     return retVal;
05478 }
05479 
05480 static Tcl_Channel
05481 PretendTclpOpenFileChannel(
05482     Tcl_Interp *interp,         /* Interpreter for error reporting; can be
05483                                  * NULL. */
05484     const char *fileName,       /* Name of file to open. */
05485     const char *modeString,     /* A list of POSIX open modes or
05486                                  * a string such as "rw". */
05487     int permissions)            /* If the open involves creating a file, with
05488                                  * what modes to create it? */
05489 {
05490     Tcl_Channel ret;
05491     int mode, seekFlag;
05492     Tcl_Obj *pathPtr;
05493     mode = TclGetOpenMode(interp, modeString, &seekFlag);
05494     if (mode == -1) {
05495         return NULL;
05496     }
05497     pathPtr = Tcl_NewStringObj(fileName, -1);
05498     Tcl_IncrRefCount(pathPtr);
05499     ret = TclpOpenFileChannel(interp, pathPtr, mode, permissions);
05500     Tcl_DecrRefCount(pathPtr);
05501     if (ret != NULL) {
05502         if (seekFlag) {
05503             if (Tcl_Seek(ret, (Tcl_WideInt)0, SEEK_END) < (Tcl_WideInt)0) {
05504                 if (interp != NULL) {
05505                     Tcl_AppendResult(interp,
05506                             "could not seek to end of file while opening \"",
05507                             fileName, "\": ", Tcl_PosixError(interp), NULL);
05508                 }
05509                 Tcl_Close(NULL, ret);
05510                 return NULL;
05511             }
05512         }
05513     }
05514     return ret;
05515 }
05516 
05517 static Tcl_Channel
05518 TestOpenFileChannelProc1(
05519     Tcl_Interp *interp,         /* Interpreter for error reporting; can be
05520                                  * NULL. */
05521     const char *fileName,       /* Name of file to open. */
05522     const char *modeString,     /* A list of POSIX open modes or
05523                                  * a string such as "rw". */
05524     int permissions)            /* If the open involves creating a file, with
05525                                  * what modes to create it? */
05526 {
05527     const char *expectname = "testOpenFileChannel1%.fil";
05528     Tcl_DString ds;
05529 
05530     Tcl_DStringInit(&ds);
05531     Tcl_JoinPath(1, &expectname, &ds);
05532 
05533     if (!strcmp(Tcl_DStringValue(&ds), fileName)) {
05534         Tcl_DStringFree(&ds);
05535         return (PretendTclpOpenFileChannel(interp,
05536                 "__testOpenFileChannel1%__.fil",
05537                 modeString, permissions));
05538     } else {
05539         Tcl_DStringFree(&ds);
05540         return NULL;
05541     }
05542 }
05543 
05544 static Tcl_Channel
05545 TestOpenFileChannelProc2(
05546     Tcl_Interp *interp,         /* Interpreter for error reporting; can be
05547                                  * NULL. */
05548     const char *fileName,       /* Name of file to open. */
05549     const char *modeString,     /* A list of POSIX open modes or
05550                                  * a string such as "rw". */
05551     int permissions)            /* If the open involves creating a file, with
05552                                  * what modes to create it? */
05553 {
05554     const char *expectname = "testOpenFileChannel2%.fil";
05555     Tcl_DString ds;
05556 
05557     Tcl_DStringInit(&ds);
05558     Tcl_JoinPath(1, &expectname, &ds);
05559 
05560     if (!strcmp(Tcl_DStringValue(&ds), fileName)) {
05561         Tcl_DStringFree(&ds);
05562         return (PretendTclpOpenFileChannel(interp,
05563                 "__testOpenFileChannel2%__.fil",
05564                 modeString, permissions));
05565     } else {
05566         Tcl_DStringFree(&ds);
05567         return (NULL);
05568     }
05569 }
05570 
05571 static Tcl_Channel
05572 TestOpenFileChannelProc3(
05573     Tcl_Interp *interp,         /* Interpreter for error reporting; can be
05574                                  * NULL. */
05575     const char *fileName,       /* Name of file to open. */
05576     const char *modeString,     /* A list of POSIX open modes or a string such
05577                                  * as "rw". */
05578     int permissions)            /* If the open involves creating a file, with
05579                                  * what modes to create it? */
05580 {
05581     const char *expectname = "testOpenFileChannel3%.fil";
05582     Tcl_DString ds;
05583 
05584     Tcl_DStringInit(&ds);
05585     Tcl_JoinPath(1, &expectname, &ds);
05586 
05587     if (!strcmp(Tcl_DStringValue(&ds), fileName)) {
05588         Tcl_DStringFree(&ds);
05589         return (PretendTclpOpenFileChannel(interp, "__testOpenFileChannel3%__.fil",
05590                 modeString, permissions));
05591     } else {
05592         Tcl_DStringFree(&ds);
05593         return (NULL);
05594     }
05595 }
05596 #endif
05597 
05598 /*
05599  *----------------------------------------------------------------------
05600  *
05601  * TestChannelCmd --
05602  *
05603  *      Implements the Tcl "testchannel" debugging command and its
05604  *      subcommands. This is part of the testing environment.
05605  *
05606  * Results:
05607  *      A standard Tcl result.
05608  *
05609  * Side effects:
05610  *      None.
05611  *
05612  *----------------------------------------------------------------------
05613  */
05614 
05615         /* ARGSUSED */
05616 static int
05617 TestChannelCmd(
05618     ClientData clientData,      /* Not used. */
05619     Tcl_Interp *interp,         /* Interpreter for result. */
05620     int argc,                   /* Count of additional args. */
05621     const char **argv)          /* Additional arg strings. */
05622 {
05623     const char *cmdName;        /* Sub command. */
05624     Tcl_HashTable *hTblPtr;     /* Hash table of channels. */
05625     Tcl_HashSearch hSearch;     /* Search variable. */
05626     Tcl_HashEntry *hPtr;        /* Search variable. */
05627     Channel *chanPtr;           /* The actual channel. */
05628     ChannelState *statePtr;     /* state info for channel */
05629     Tcl_Channel chan;           /* The opaque type. */
05630     size_t len;                 /* Length of subcommand string. */
05631     int IOQueued;               /* How much IO is queued inside channel? */
05632     char buf[TCL_INTEGER_SPACE];/* For sprintf. */
05633     int mode;                   /* rw mode of the channel */
05634 
05635     if (argc < 2) {
05636         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
05637                 " subcommand ?additional args..?\"", NULL);
05638         return TCL_ERROR;
05639     }
05640     cmdName = argv[1];
05641     len = strlen(cmdName);
05642 
05643     chanPtr = NULL;
05644 
05645     if (argc > 2) {
05646         if ((cmdName[0] == 's') && (strncmp(cmdName, "splice", len) == 0)) {
05647             /* For splice access the pool of detached channels.
05648              * Locate channel, remove from the list.
05649              */
05650 
05651             TestChannel **nextPtrPtr, *curPtr;
05652 
05653             chan = (Tcl_Channel) NULL;
05654             for (nextPtrPtr = &firstDetached, curPtr = firstDetached;
05655                  curPtr != NULL;
05656                  nextPtrPtr = &(curPtr->nextPtr), curPtr = curPtr->nextPtr) {
05657 
05658                 if (strcmp(argv[2], Tcl_GetChannelName(curPtr->chan)) == 0) {
05659                     *nextPtrPtr = curPtr->nextPtr;
05660                     curPtr->nextPtr = NULL;
05661                     chan = curPtr->chan;
05662                     ckfree((char *) curPtr);
05663                     break;
05664                 }
05665             }
05666         } else {
05667             chan = Tcl_GetChannel(interp, argv[2], &mode);
05668         }
05669         if (chan == (Tcl_Channel) NULL) {
05670             return TCL_ERROR;
05671         }
05672         chanPtr         = (Channel *) chan;
05673         statePtr        = chanPtr->state;
05674         chanPtr         = statePtr->topChanPtr;
05675         chan            = (Tcl_Channel) chanPtr;
05676     } else {
05677         /* lint */
05678         statePtr        = NULL;
05679         chan            = NULL;
05680     }
05681 
05682     if ((cmdName[0] == 's') && (strncmp(cmdName, "setchannelerror", len) == 0)) {
05683 
05684         Tcl_Obj *msg = Tcl_NewStringObj(argv[3],-1);
05685 
05686         Tcl_IncrRefCount(msg);
05687         Tcl_SetChannelError(chan, msg);
05688         Tcl_DecrRefCount(msg);
05689 
05690         Tcl_GetChannelError(chan, &msg);
05691         Tcl_SetObjResult(interp, msg);
05692         Tcl_DecrRefCount(msg);
05693         return TCL_OK;
05694     }
05695     if ((cmdName[0] == 's') && (strncmp(cmdName, "setchannelerrorinterp", len) == 0)) {
05696 
05697         Tcl_Obj *msg = Tcl_NewStringObj(argv[3],-1);
05698 
05699         Tcl_IncrRefCount(msg);
05700         Tcl_SetChannelErrorInterp(interp, msg);
05701         Tcl_DecrRefCount(msg);
05702 
05703         Tcl_GetChannelErrorInterp(interp, &msg);
05704         Tcl_SetObjResult(interp, msg);
05705         Tcl_DecrRefCount(msg);
05706         return TCL_OK;
05707     }
05708 
05709     /*
05710      * "cut" is actually more a simplified detach facility as provided by the
05711      * Thread package. Without the safeguards of a regular command (no
05712      * checking that the command is truly cut'able, no mutexes for
05713      * thread-safety). Its complementary command is "splice", see below.
05714      */
05715 
05716     if ((cmdName[0] == 'c') && (strncmp(cmdName, "cut", len) == 0)) {
05717         TestChannel *det;
05718 
05719         if (argc != 3) {
05720             Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
05721                     " cut channelName\"", NULL);
05722             return TCL_ERROR;
05723         }
05724 
05725         Tcl_RegisterChannel(NULL, chan); /* prevent closing */
05726         Tcl_UnregisterChannel(interp, chan);
05727 
05728         Tcl_CutChannel(chan);
05729 
05730         /* Remember the channel in the pool of detached channels */
05731 
05732         det = (TestChannel *) ckalloc(sizeof(TestChannel));
05733         det->chan     = chan;
05734         det->nextPtr  = firstDetached;
05735         firstDetached = det;
05736 
05737         return TCL_OK;
05738     }
05739 
05740     if ((cmdName[0] == 'c') &&
05741             (strncmp(cmdName, "clearchannelhandlers", len) == 0)) {
05742         if (argc != 3) {
05743             Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
05744                     " clearchannelhandlers channelName\"", NULL);
05745             return TCL_ERROR;
05746         }
05747         Tcl_ClearChannelHandlers(chan);
05748         return TCL_OK;
05749     }
05750 
05751     if ((cmdName[0] == 'i') && (strncmp(cmdName, "info", len) == 0)) {
05752         if (argc != 3) {
05753             Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
05754                     " info channelName\"", NULL);
05755             return TCL_ERROR;
05756         }
05757         Tcl_AppendElement(interp, argv[2]);
05758         Tcl_AppendElement(interp, Tcl_ChannelName(chanPtr->typePtr));
05759         if (statePtr->flags & TCL_READABLE) {
05760             Tcl_AppendElement(interp, "read");
05761         } else {
05762             Tcl_AppendElement(interp, "");
05763         }
05764         if (statePtr->flags & TCL_WRITABLE) {
05765             Tcl_AppendElement(interp, "write");
05766         } else {
05767             Tcl_AppendElement(interp, "");
05768         }
05769         if (statePtr->flags & CHANNEL_NONBLOCKING) {
05770             Tcl_AppendElement(interp, "nonblocking");
05771         } else {
05772             Tcl_AppendElement(interp, "blocking");
05773         }
05774         if (statePtr->flags & CHANNEL_LINEBUFFERED) {
05775             Tcl_AppendElement(interp, "line");
05776         } else if (statePtr->flags & CHANNEL_UNBUFFERED) {
05777             Tcl_AppendElement(interp, "none");
05778         } else {
05779             Tcl_AppendElement(interp, "full");
05780         }
05781         if (statePtr->flags & BG_FLUSH_SCHEDULED) {
05782             Tcl_AppendElement(interp, "async_flush");
05783         } else {
05784             Tcl_AppendElement(interp, "");
05785         }
05786         if (statePtr->flags & CHANNEL_EOF) {
05787             Tcl_AppendElement(interp, "eof");
05788         } else {
05789             Tcl_AppendElement(interp, "");
05790         }
05791         if (statePtr->flags & CHANNEL_BLOCKED) {
05792             Tcl_AppendElement(interp, "blocked");
05793         } else {
05794             Tcl_AppendElement(interp, "unblocked");
05795         }
05796         if (statePtr->inputTranslation == TCL_TRANSLATE_AUTO) {
05797             Tcl_AppendElement(interp, "auto");
05798             if (statePtr->flags & INPUT_SAW_CR) {
05799                 Tcl_AppendElement(interp, "saw_cr");
05800             } else {
05801                 Tcl_AppendElement(interp, "");
05802             }
05803         } else if (statePtr->inputTranslation == TCL_TRANSLATE_LF) {
05804             Tcl_AppendElement(interp, "lf");
05805             Tcl_AppendElement(interp, "");
05806         } else if (statePtr->inputTranslation == TCL_TRANSLATE_CR) {
05807             Tcl_AppendElement(interp, "cr");
05808             Tcl_AppendElement(interp, "");
05809         } else if (statePtr->inputTranslation == TCL_TRANSLATE_CRLF) {
05810             Tcl_AppendElement(interp, "crlf");
05811             if (statePtr->flags & INPUT_SAW_CR) {
05812                 Tcl_AppendElement(interp, "queued_cr");
05813             } else {
05814                 Tcl_AppendElement(interp, "");
05815             }
05816         }
05817         if (statePtr->outputTranslation == TCL_TRANSLATE_AUTO) {
05818             Tcl_AppendElement(interp, "auto");
05819         } else if (statePtr->outputTranslation == TCL_TRANSLATE_LF) {
05820             Tcl_AppendElement(interp, "lf");
05821         } else if (statePtr->outputTranslation == TCL_TRANSLATE_CR) {
05822             Tcl_AppendElement(interp, "cr");
05823         } else if (statePtr->outputTranslation == TCL_TRANSLATE_CRLF) {
05824             Tcl_AppendElement(interp, "crlf");
05825         }
05826         IOQueued = Tcl_InputBuffered(chan);
05827         TclFormatInt(buf, IOQueued);
05828         Tcl_AppendElement(interp, buf);
05829 
05830         IOQueued = Tcl_OutputBuffered(chan);
05831         TclFormatInt(buf, IOQueued);
05832         Tcl_AppendElement(interp, buf);
05833 
05834         TclFormatInt(buf, (int)Tcl_Tell(chan));
05835         Tcl_AppendElement(interp, buf);
05836 
05837         TclFormatInt(buf, statePtr->refCount);
05838         Tcl_AppendElement(interp, buf);
05839 
05840         return TCL_OK;
05841     }
05842 
05843     if ((cmdName[0] == 'i') &&
05844             (strncmp(cmdName, "inputbuffered", len) == 0)) {
05845         if (argc != 3) {
05846             Tcl_AppendResult(interp, "channel name required", NULL);
05847             return TCL_ERROR;
05848         }
05849         IOQueued = Tcl_InputBuffered(chan);
05850         TclFormatInt(buf, IOQueued);
05851         Tcl_AppendResult(interp, buf, NULL);
05852         return TCL_OK;
05853     }
05854 
05855     if ((cmdName[0] == 'i') && (strncmp(cmdName, "isshared", len) == 0)) {
05856         if (argc != 3) {
05857             Tcl_AppendResult(interp, "channel name required", NULL);
05858             return TCL_ERROR;
05859         }
05860 
05861         TclFormatInt(buf, Tcl_IsChannelShared(chan));
05862         Tcl_AppendResult(interp, buf, NULL);
05863         return TCL_OK;
05864     }
05865 
05866     if ((cmdName[0] == 'i') && (strncmp(cmdName, "isstandard", len) == 0)) {
05867         if (argc != 3) {
05868             Tcl_AppendResult(interp, "channel name required", NULL);
05869             return TCL_ERROR;
05870         }
05871 
05872         TclFormatInt(buf, Tcl_IsStandardChannel(chan));
05873         Tcl_AppendResult(interp, buf, NULL);
05874         return TCL_OK;
05875     }
05876 
05877     if ((cmdName[0] == 'm') && (strncmp(cmdName, "mode", len) == 0)) {
05878         if (argc != 3) {
05879             Tcl_AppendResult(interp, "channel name required", NULL);
05880             return TCL_ERROR;
05881         }
05882 
05883         if (statePtr->flags & TCL_READABLE) {
05884             Tcl_AppendElement(interp, "read");
05885         } else {
05886             Tcl_AppendElement(interp, "");
05887         }
05888         if (statePtr->flags & TCL_WRITABLE) {
05889             Tcl_AppendElement(interp, "write");
05890         } else {
05891             Tcl_AppendElement(interp, "");
05892         }
05893         return TCL_OK;
05894     }
05895 
05896     if ((cmdName[0] == 'm') && (strncmp(cmdName, "mthread", len) == 0)) {
05897         if (argc != 3) {
05898             Tcl_AppendResult(interp, "channel name required", NULL);
05899             return TCL_ERROR;
05900         }
05901 
05902         TclFormatInt(buf, (long) Tcl_GetChannelThread(chan));
05903         Tcl_AppendResult(interp, buf, NULL);
05904         return TCL_OK;
05905     }
05906 
05907     if ((cmdName[0] == 'n') && (strncmp(cmdName, "name", len) == 0)) {
05908         if (argc != 3) {
05909             Tcl_AppendResult(interp, "channel name required", NULL);
05910             return TCL_ERROR;
05911         }
05912         Tcl_AppendResult(interp, statePtr->channelName, NULL);
05913         return TCL_OK;
05914     }
05915 
05916     if ((cmdName[0] == 'o') && (strncmp(cmdName, "open", len) == 0)) {
05917         hTblPtr = (Tcl_HashTable *) Tcl_GetAssocData(interp, "tclIO", NULL);
05918         if (hTblPtr == NULL) {
05919             return TCL_OK;
05920         }
05921         for (hPtr = Tcl_FirstHashEntry(hTblPtr, &hSearch);
05922              hPtr != NULL;
05923              hPtr = Tcl_NextHashEntry(&hSearch)) {
05924             Tcl_AppendElement(interp, Tcl_GetHashKey(hTblPtr, hPtr));
05925         }
05926         return TCL_OK;
05927     }
05928 
05929     if ((cmdName[0] == 'o') &&
05930             (strncmp(cmdName, "outputbuffered", len) == 0)) {
05931         if (argc != 3) {
05932             Tcl_AppendResult(interp, "channel name required", NULL);
05933             return TCL_ERROR;
05934         }
05935 
05936         IOQueued = Tcl_OutputBuffered(chan);
05937         TclFormatInt(buf, IOQueued);
05938         Tcl_AppendResult(interp, buf, NULL);
05939         return TCL_OK;
05940     }
05941 
05942     if ((cmdName[0] == 'q') &&
05943             (strncmp(cmdName, "queuedcr", len) == 0)) {
05944         if (argc != 3) {
05945             Tcl_AppendResult(interp, "channel name required", NULL);
05946             return TCL_ERROR;
05947         }
05948 
05949         Tcl_AppendResult(interp,
05950                 (statePtr->flags & INPUT_SAW_CR) ? "1" : "0", NULL);
05951         return TCL_OK;
05952     }
05953 
05954     if ((cmdName[0] == 'r') && (strncmp(cmdName, "readable", len) == 0)) {
05955         hTblPtr = (Tcl_HashTable *) Tcl_GetAssocData(interp, "tclIO", NULL);
05956         if (hTblPtr == NULL) {
05957             return TCL_OK;
05958         }
05959         for (hPtr = Tcl_FirstHashEntry(hTblPtr, &hSearch);
05960              hPtr != NULL;
05961              hPtr = Tcl_NextHashEntry(&hSearch)) {
05962             chanPtr  = (Channel *) Tcl_GetHashValue(hPtr);
05963             statePtr = chanPtr->state;
05964             if (statePtr->flags & TCL_READABLE) {
05965                 Tcl_AppendElement(interp, Tcl_GetHashKey(hTblPtr, hPtr));
05966             }
05967         }
05968         return TCL_OK;
05969     }
05970 
05971     if ((cmdName[0] == 'r') && (strncmp(cmdName, "refcount", len) == 0)) {
05972         if (argc != 3) {
05973             Tcl_AppendResult(interp, "channel name required", NULL);
05974             return TCL_ERROR;
05975         }
05976 
05977         TclFormatInt(buf, statePtr->refCount);
05978         Tcl_AppendResult(interp, buf, NULL);
05979         return TCL_OK;
05980     }
05981 
05982     /*
05983      * "splice" is actually more a simplified attach facility as provided by
05984      * the Thread package. Without the safeguards of a regular command (no
05985      * checking that the command is truly cut'able, no mutexes for
05986      * thread-safety). Its complementary command is "cut", see above.
05987      */
05988 
05989     if ((cmdName[0] == 's') && (strncmp(cmdName, "splice", len) == 0)) {
05990         if (argc != 3) {
05991             Tcl_AppendResult(interp, "channel name required", NULL);
05992             return TCL_ERROR;
05993         }
05994 
05995         Tcl_SpliceChannel(chan);
05996 
05997         Tcl_RegisterChannel(interp, chan);
05998         Tcl_UnregisterChannel(NULL, chan);
05999 
06000         return TCL_OK;
06001     }
06002 
06003     if ((cmdName[0] == 't') && (strncmp(cmdName, "type", len) == 0)) {
06004         if (argc != 3) {
06005             Tcl_AppendResult(interp, "channel name required", NULL);
06006             return TCL_ERROR;
06007         }
06008         Tcl_AppendResult(interp, Tcl_ChannelName(chanPtr->typePtr), NULL);
06009         return TCL_OK;
06010     }
06011 
06012     if ((cmdName[0] == 'w') && (strncmp(cmdName, "writable", len) == 0)) {
06013         hTblPtr = (Tcl_HashTable *) Tcl_GetAssocData(interp, "tclIO", NULL);
06014         if (hTblPtr == NULL) {
06015             return TCL_OK;
06016         }
06017         for (hPtr = Tcl_FirstHashEntry(hTblPtr, &hSearch);
06018                 hPtr != NULL; hPtr = Tcl_NextHashEntry(&hSearch)) {
06019             chanPtr = (Channel *) Tcl_GetHashValue(hPtr);
06020             statePtr = chanPtr->state;
06021             if (statePtr->flags & TCL_WRITABLE) {
06022                 Tcl_AppendElement(interp, Tcl_GetHashKey(hTblPtr, hPtr));
06023             }
06024         }
06025         return TCL_OK;
06026     }
06027 
06028     if ((cmdName[0] == 't') && (strncmp(cmdName, "transform", len) == 0)) {
06029         /*
06030          * Syntax: transform channel -command command
06031          */
06032 
06033         if (argc != 5) {
06034             Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
06035                     " transform channelId -command cmd\"", NULL);
06036             return TCL_ERROR;
06037         }
06038         if (strcmp(argv[3], "-command") != 0) {
06039             Tcl_AppendResult(interp, "bad argument \"", argv[3],
06040                     "\": should be \"-command\"", NULL);
06041             return TCL_ERROR;
06042         }
06043 
06044         return TclChannelTransform(interp, chan,
06045                 Tcl_NewStringObj(argv[4], -1));
06046     }
06047 
06048     if ((cmdName[0] == 'u') && (strncmp(cmdName, "unstack", len) == 0)) {
06049         /*
06050          * Syntax: unstack channel
06051          */
06052 
06053         if (argc != 3) {
06054             Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
06055                     " unstack channel\"", NULL);
06056             return TCL_ERROR;
06057         }
06058         return Tcl_UnstackChannel(interp, chan);
06059     }
06060 
06061     Tcl_AppendResult(interp, "bad option \"", cmdName, "\": should be "
06062             "cut, clearchannelhandlers, info, isshared, mode, open, "
06063             "readable, splice, writable, transform, unstack", NULL);
06064     return TCL_ERROR;
06065 }
06066 
06067 /*
06068  *----------------------------------------------------------------------
06069  *
06070  * TestChannelEventCmd --
06071  *
06072  *      This procedure implements the "testchannelevent" command. It is used
06073  *      to test the Tcl channel event mechanism.
06074  *
06075  * Results:
06076  *      A standard Tcl result.
06077  *
06078  * Side effects:
06079  *      Creates, deletes and returns channel event handlers.
06080  *
06081  *----------------------------------------------------------------------
06082  */
06083 
06084         /* ARGSUSED */
06085 static int
06086 TestChannelEventCmd(
06087     ClientData dummy,           /* Not used. */
06088     Tcl_Interp *interp,         /* Current interpreter. */
06089     int argc,                   /* Number of arguments. */
06090     const char **argv)          /* Argument strings. */
06091 {
06092     Tcl_Obj *resultListPtr;
06093     Channel *chanPtr;
06094     ChannelState *statePtr;     /* state info for channel */
06095     EventScriptRecord *esPtr, *prevEsPtr, *nextEsPtr;
06096     const char *cmd;
06097     int index, i, mask, len;
06098 
06099     if ((argc < 3) || (argc > 5)) {
06100         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
06101                 " channelName cmd ?arg1? ?arg2?\"", NULL);
06102         return TCL_ERROR;
06103     }
06104     chanPtr = (Channel *) Tcl_GetChannel(interp, argv[1], NULL);
06105     if (chanPtr == NULL) {
06106         return TCL_ERROR;
06107     }
06108     statePtr = chanPtr->state;
06109 
06110     cmd = argv[2];
06111     len = strlen(cmd);
06112     if ((cmd[0] == 'a') && (strncmp(cmd, "add", (unsigned) len) == 0)) {
06113         if (argc != 5) {
06114             Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
06115                     " channelName add eventSpec script\"", NULL);
06116             return TCL_ERROR;
06117         }
06118         if (strcmp(argv[3], "readable") == 0) {
06119             mask = TCL_READABLE;
06120         } else if (strcmp(argv[3], "writable") == 0) {
06121             mask = TCL_WRITABLE;
06122         } else if (strcmp(argv[3], "none") == 0) {
06123             mask = 0;
06124         } else {
06125             Tcl_AppendResult(interp, "bad event name \"", argv[3],
06126                     "\": must be readable, writable, or none", NULL);
06127             return TCL_ERROR;
06128         }
06129 
06130         esPtr = (EventScriptRecord *) ckalloc((unsigned)
06131                 sizeof(EventScriptRecord));
06132         esPtr->nextPtr = statePtr->scriptRecordPtr;
06133         statePtr->scriptRecordPtr = esPtr;
06134 
06135         esPtr->chanPtr = chanPtr;
06136         esPtr->interp = interp;
06137         esPtr->mask = mask;
06138         esPtr->scriptPtr = Tcl_NewStringObj(argv[4], -1);
06139         Tcl_IncrRefCount(esPtr->scriptPtr);
06140 
06141         Tcl_CreateChannelHandler((Tcl_Channel) chanPtr, mask,
06142                 TclChannelEventScriptInvoker, (ClientData) esPtr);
06143 
06144         return TCL_OK;
06145     }
06146 
06147     if ((cmd[0] == 'd') && (strncmp(cmd, "delete", (unsigned) len) == 0)) {
06148         if (argc != 4) {
06149             Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
06150                     " channelName delete index\"", NULL);
06151             return TCL_ERROR;
06152         }
06153         if (Tcl_GetInt(interp, argv[3], &index) == TCL_ERROR) {
06154             return TCL_ERROR;
06155         }
06156         if (index < 0) {
06157             Tcl_AppendResult(interp, "bad event index: ", argv[3],
06158                     ": must be nonnegative", NULL);
06159             return TCL_ERROR;
06160         }
06161         for (i = 0, esPtr = statePtr->scriptRecordPtr;
06162              (i < index) && (esPtr != NULL);
06163              i++, esPtr = esPtr->nextPtr) {
06164             /* Empty loop body. */
06165         }
06166         if (esPtr == NULL) {
06167             Tcl_AppendResult(interp, "bad event index ", argv[3],
06168                     ": out of range", NULL);
06169             return TCL_ERROR;
06170         }
06171         if (esPtr == statePtr->scriptRecordPtr) {
06172             statePtr->scriptRecordPtr = esPtr->nextPtr;
06173         } else {
06174             for (prevEsPtr = statePtr->scriptRecordPtr;
06175                  (prevEsPtr != NULL) &&
06176                      (prevEsPtr->nextPtr != esPtr);
06177                  prevEsPtr = prevEsPtr->nextPtr) {
06178                 /* Empty loop body. */
06179             }
06180             if (prevEsPtr == NULL) {
06181                 Tcl_Panic("TestChannelEventCmd: damaged event script list");
06182             }
06183             prevEsPtr->nextPtr = esPtr->nextPtr;
06184         }
06185         Tcl_DeleteChannelHandler((Tcl_Channel) chanPtr,
06186                 TclChannelEventScriptInvoker, (ClientData) esPtr);
06187         Tcl_DecrRefCount(esPtr->scriptPtr);
06188         ckfree((char *) esPtr);
06189 
06190         return TCL_OK;
06191     }
06192 
06193     if ((cmd[0] == 'l') && (strncmp(cmd, "list", (unsigned) len) == 0)) {
06194         if (argc != 3) {
06195             Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
06196                     " channelName list\"", NULL);
06197             return TCL_ERROR;
06198         }
06199         resultListPtr = Tcl_GetObjResult(interp);
06200         for (esPtr = statePtr->scriptRecordPtr;
06201              esPtr != NULL;
06202              esPtr = esPtr->nextPtr) {
06203             if (esPtr->mask) {
06204                 Tcl_ListObjAppendElement(interp, resultListPtr, Tcl_NewStringObj(
06205                     (esPtr->mask == TCL_READABLE) ? "readable" : "writable", -1));
06206             } else {
06207                 Tcl_ListObjAppendElement(interp, resultListPtr,
06208                         Tcl_NewStringObj("none", -1));
06209             }
06210             Tcl_ListObjAppendElement(interp, resultListPtr, esPtr->scriptPtr);
06211         }
06212         Tcl_SetObjResult(interp, resultListPtr);
06213         return TCL_OK;
06214     }
06215 
06216     if ((cmd[0] == 'r') && (strncmp(cmd, "removeall", (unsigned) len) == 0)) {
06217         if (argc != 3) {
06218             Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
06219                     " channelName removeall\"", NULL);
06220             return TCL_ERROR;
06221         }
06222         for (esPtr = statePtr->scriptRecordPtr;
06223              esPtr != NULL;
06224              esPtr = nextEsPtr) {
06225             nextEsPtr = esPtr->nextPtr;
06226             Tcl_DeleteChannelHandler((Tcl_Channel) chanPtr,
06227                     TclChannelEventScriptInvoker, (ClientData) esPtr);
06228             Tcl_DecrRefCount(esPtr->scriptPtr);
06229             ckfree((char *) esPtr);
06230         }
06231         statePtr->scriptRecordPtr = NULL;
06232         return TCL_OK;
06233     }
06234 
06235     if  ((cmd[0] == 's') && (strncmp(cmd, "set", (unsigned) len) == 0)) {
06236         if (argc != 5) {
06237             Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
06238                     " channelName delete index event\"", NULL);
06239             return TCL_ERROR;
06240         }
06241         if (Tcl_GetInt(interp, argv[3], &index) == TCL_ERROR) {
06242             return TCL_ERROR;
06243         }
06244         if (index < 0) {
06245             Tcl_AppendResult(interp, "bad event index: ", argv[3],
06246                     ": must be nonnegative", NULL);
06247             return TCL_ERROR;
06248         }
06249         for (i = 0, esPtr = statePtr->scriptRecordPtr;
06250              (i < index) && (esPtr != NULL);
06251              i++, esPtr = esPtr->nextPtr) {
06252             /* Empty loop body. */
06253         }
06254         if (esPtr == NULL) {
06255             Tcl_AppendResult(interp, "bad event index ", argv[3],
06256                     ": out of range", NULL);
06257             return TCL_ERROR;
06258         }
06259 
06260         if (strcmp(argv[4], "readable") == 0) {
06261             mask = TCL_READABLE;
06262         } else if (strcmp(argv[4], "writable") == 0) {
06263             mask = TCL_WRITABLE;
06264         } else if (strcmp(argv[4], "none") == 0) {
06265             mask = 0;
06266         } else {
06267             Tcl_AppendResult(interp, "bad event name \"", argv[4],
06268                     "\": must be readable, writable, or none", NULL);
06269             return TCL_ERROR;
06270         }
06271         esPtr->mask = mask;
06272         Tcl_CreateChannelHandler((Tcl_Channel) chanPtr, mask,
06273                 TclChannelEventScriptInvoker, (ClientData) esPtr);
06274         return TCL_OK;
06275     }
06276     Tcl_AppendResult(interp, "bad command ", cmd, ", must be one of "
06277             "add, delete, list, set, or removeall", NULL);
06278     return TCL_ERROR;
06279 }
06280 
06281 /*
06282  *----------------------------------------------------------------------
06283  *
06284  * TestWrongNumArgsObjCmd --
06285  *
06286  *      Test the Tcl_WrongNumArgs function.
06287  *
06288  * Results:
06289  *      Standard Tcl result.
06290  *
06291  * Side effects:
06292  *      Sets interpreter result.
06293  *
06294  *----------------------------------------------------------------------
06295  */
06296 
06297 static int
06298 TestWrongNumArgsObjCmd(
06299     ClientData dummy,           /* Not used. */
06300     Tcl_Interp *interp,         /* Current interpreter. */
06301     int objc,                   /* Number of arguments. */
06302     Tcl_Obj *const objv[])      /* Argument objects. */
06303 {
06304     int i, length;
06305     char *msg;
06306 
06307     if (objc < 3) {
06308         /*
06309          * Don't use Tcl_WrongNumArgs here, as that is the function
06310          * we want to test!
06311          */
06312         Tcl_SetResult(interp, "insufficient arguments", TCL_STATIC);
06313         return TCL_ERROR;
06314     }
06315 
06316     if (Tcl_GetIntFromObj(interp, objv[1], &i) != TCL_OK) {
06317         return TCL_ERROR;
06318     }
06319 
06320     msg = Tcl_GetStringFromObj(objv[2], &length);
06321     if (length == 0) {
06322         msg = NULL;
06323     }
06324 
06325     if (i > objc - 3) {
06326         /*
06327          * Asked for more arguments than were given.
06328          */
06329         Tcl_SetResult(interp, "insufficient arguments", TCL_STATIC);
06330         return TCL_ERROR;
06331     }
06332 
06333     Tcl_WrongNumArgs(interp, i, &(objv[3]), msg);
06334     return TCL_OK;
06335 }
06336 
06337 /*
06338  *----------------------------------------------------------------------
06339  *
06340  * TestGetIndexFromObjStructObjCmd --
06341  *
06342  *      Test the Tcl_GetIndexFromObjStruct function.
06343  *
06344  * Results:
06345  *      Standard Tcl result.
06346  *
06347  * Side effects:
06348  *      Sets interpreter result.
06349  *
06350  *----------------------------------------------------------------------
06351  */
06352 
06353 static int
06354 TestGetIndexFromObjStructObjCmd(
06355     ClientData dummy,           /* Not used. */
06356     Tcl_Interp *interp,         /* Current interpreter. */
06357     int objc,                   /* Number of arguments. */
06358     Tcl_Obj *const objv[])      /* Argument objects. */
06359 {
06360     char *ary[] = {
06361         "a", "b", "c", "d", "e", "f", NULL, NULL
06362     };
06363     int idx,target;
06364 
06365     if (objc != 3) {
06366         Tcl_WrongNumArgs(interp, 1, objv, "argument targetvalue");
06367         return TCL_ERROR;
06368     }
06369     if (Tcl_GetIndexFromObjStruct(interp, objv[1], ary, 2*sizeof(char *),
06370             "dummy", 0, &idx) != TCL_OK) {
06371         return TCL_ERROR;
06372     }
06373     if (Tcl_GetIntFromObj(interp, objv[2], &target) != TCL_OK) {
06374         return TCL_ERROR;
06375     }
06376     if (idx != target) {
06377         char buffer[64];
06378         sprintf(buffer, "%d", idx);
06379         Tcl_AppendResult(interp, "index value comparison failed: got ",
06380                 buffer, NULL);
06381         sprintf(buffer, "%d", target);
06382         Tcl_AppendResult(interp, " when ", buffer, " expected", NULL);
06383         return TCL_ERROR;
06384     }
06385     Tcl_WrongNumArgs(interp, 3, objv, NULL);
06386     return TCL_OK;
06387 }
06388 
06389 /*
06390  *----------------------------------------------------------------------
06391  *
06392  * TestFilesystemObjCmd --
06393  *
06394  *      This procedure implements the "testfilesystem" command. It is used to
06395  *      test Tcl_FSRegister, Tcl_FSUnregister, and can be used to test that
06396  *      the pluggable filesystem works.
06397  *
06398  * Results:
06399  *      A standard Tcl result.
06400  *
06401  * Side effects:
06402  *      Inserts or removes a filesystem from Tcl's stack.
06403  *
06404  *----------------------------------------------------------------------
06405  */
06406 
06407 static int
06408 TestFilesystemObjCmd(
06409     ClientData dummy,
06410     Tcl_Interp *interp,
06411     int objc,
06412     Tcl_Obj *const objv[])
06413 {
06414     int res, boolVal;
06415     char *msg;
06416 
06417     if (objc != 2) {
06418         Tcl_WrongNumArgs(interp, 1, objv, "boolean");
06419         return TCL_ERROR;
06420     }
06421     if (Tcl_GetBooleanFromObj(interp, objv[1], &boolVal) != TCL_OK) {
06422         return TCL_ERROR;
06423     }
06424     if (boolVal) {
06425         res = Tcl_FSRegister((ClientData)interp, &testReportingFilesystem);
06426         msg = (res == TCL_OK) ? "registered" : "failed";
06427     } else {
06428         res = Tcl_FSUnregister(&testReportingFilesystem);
06429         msg = (res == TCL_OK) ? "unregistered" : "failed";
06430     }
06431     Tcl_SetResult(interp, msg, TCL_VOLATILE);
06432     return res;
06433 }
06434 
06435 static int
06436 TestReportInFilesystem(
06437     Tcl_Obj *pathPtr,
06438     ClientData *clientDataPtr)
06439 {
06440     static Tcl_Obj *lastPathPtr = NULL;
06441     Tcl_Obj *newPathPtr;
06442 
06443     if (pathPtr == lastPathPtr) {
06444         /* Reject all files second time around */
06445         return -1;
06446     }
06447 
06448     /* Try to claim all files first time around */
06449 
06450     newPathPtr = Tcl_DuplicateObj(pathPtr);
06451     lastPathPtr = newPathPtr;
06452     Tcl_IncrRefCount(newPathPtr);
06453     if (Tcl_FSGetFileSystemForPath(newPathPtr) == NULL) {
06454         /* Nothing claimed it. Therefore we don't either */
06455         Tcl_DecrRefCount(newPathPtr);
06456         lastPathPtr = NULL;
06457         return -1;
06458     }
06459     lastPathPtr = NULL;
06460     *clientDataPtr = (ClientData) newPathPtr;
06461     return TCL_OK;
06462 }
06463 
06464 /*
06465  * Simple helper function to extract the native vfs representation of a path
06466  * object, or NULL if no such representation exists.
06467  */
06468 
06469 static Tcl_Obj *
06470 TestReportGetNativePath(
06471     Tcl_Obj *pathPtr)
06472 {
06473     return (Tcl_Obj*) Tcl_FSGetInternalRep(pathPtr, &testReportingFilesystem);
06474 }
06475 
06476 static void
06477 TestReportFreeInternalRep(
06478     ClientData clientData)
06479 {
06480     Tcl_Obj *nativeRep = (Tcl_Obj *) clientData;
06481 
06482     if (nativeRep != NULL) {
06483         /* Free the path */
06484         Tcl_DecrRefCount(nativeRep);
06485     }
06486 }
06487 
06488 static ClientData
06489 TestReportDupInternalRep(
06490     ClientData clientData)
06491 {
06492     Tcl_Obj *original = (Tcl_Obj *) clientData;
06493 
06494     Tcl_IncrRefCount(original);
06495     return clientData;
06496 }
06497 
06498 static void
06499 TestReport(
06500     const char *cmd,
06501     Tcl_Obj *path,
06502     Tcl_Obj *arg2)
06503 {
06504     Tcl_Interp *interp = (Tcl_Interp *) Tcl_FSData(&testReportingFilesystem);
06505 
06506     if (interp == NULL) {
06507         /* This is bad, but not much we can do about it */
06508     } else {
06509         /*
06510          * No idea why I decided to program this up using the old string-based
06511          * API, but there you go. We should convert it to objects.
06512          */
06513 
06514         Tcl_SavedResult savedResult;
06515         Tcl_DString ds;
06516 
06517         Tcl_DStringInit(&ds);
06518         Tcl_DStringAppend(&ds, "lappend filesystemReport ", -1);
06519         Tcl_DStringStartSublist(&ds);
06520         Tcl_DStringAppendElement(&ds, cmd);
06521         if (path != NULL) {
06522             Tcl_DStringAppendElement(&ds, Tcl_GetString(path));
06523         }
06524         if (arg2 != NULL) {
06525             Tcl_DStringAppendElement(&ds, Tcl_GetString(arg2));
06526         }
06527         Tcl_DStringEndSublist(&ds);
06528         Tcl_SaveResult(interp, &savedResult);
06529         Tcl_Eval(interp, Tcl_DStringValue(&ds));
06530         Tcl_DStringFree(&ds);
06531         Tcl_RestoreResult(interp, &savedResult);
06532    }
06533 }
06534 
06535 static int
06536 TestReportStat(
06537     Tcl_Obj *path,              /* Path of file to stat (in current CP). */
06538     Tcl_StatBuf *buf)           /* Filled with results of stat call. */
06539 {
06540     TestReport("stat", path, NULL);
06541     return Tcl_FSStat(TestReportGetNativePath(path), buf);
06542 }
06543 
06544 static int
06545 TestReportLstat(
06546     Tcl_Obj *path,              /* Path of file to stat (in current CP). */
06547     Tcl_StatBuf *buf)           /* Filled with results of stat call. */
06548 {
06549     TestReport("lstat", path, NULL);
06550     return Tcl_FSLstat(TestReportGetNativePath(path), buf);
06551 }
06552 
06553 static int
06554 TestReportAccess(
06555     Tcl_Obj *path,              /* Path of file to access (in current CP). */
06556     int mode)                   /* Permission setting. */
06557 {
06558     TestReport("access", path, NULL);
06559     return Tcl_FSAccess(TestReportGetNativePath(path), mode);
06560 }
06561 
06562 static Tcl_Channel
06563 TestReportOpenFileChannel(
06564     Tcl_Interp *interp,         /* Interpreter for error reporting; can be
06565                                  * NULL. */
06566     Tcl_Obj *fileName,          /* Name of file to open. */
06567     int mode,                   /* POSIX open mode. */
06568     int permissions)            /* If the open involves creating a file, with
06569                                  * what modes to create it? */
06570 {
06571     TestReport("open", fileName, NULL);
06572     return TclpOpenFileChannel(interp, TestReportGetNativePath(fileName),
06573             mode, permissions);
06574 }
06575 
06576 static int
06577 TestReportMatchInDirectory(
06578     Tcl_Interp *interp,         /* Interpreter for error messages. */
06579     Tcl_Obj *resultPtr,         /* Object to lappend results. */
06580     Tcl_Obj *dirPtr,            /* Contains path to directory to search. */
06581     const char *pattern,        /* Pattern to match against. */
06582     Tcl_GlobTypeData *types)    /* Object containing list of acceptable types.
06583                                  * May be NULL. */
06584 {
06585     if (types != NULL && types->type & TCL_GLOB_TYPE_MOUNT) {
06586         TestReport("matchmounts", dirPtr, NULL);
06587         return TCL_OK;
06588     } else {
06589         TestReport("matchindirectory", dirPtr, NULL);
06590         return Tcl_FSMatchInDirectory(interp, resultPtr,
06591                 TestReportGetNativePath(dirPtr), pattern, types);
06592     }
06593 }
06594 
06595 static int
06596 TestReportChdir(
06597     Tcl_Obj *dirName)
06598 {
06599     TestReport("chdir", dirName, NULL);
06600     return Tcl_FSChdir(TestReportGetNativePath(dirName));
06601 }
06602 
06603 static int
06604 TestReportLoadFile(
06605     Tcl_Interp *interp,         /* Used for error reporting. */
06606     Tcl_Obj *fileName,          /* Name of the file containing the desired
06607                                  * code. */
06608     Tcl_LoadHandle *handlePtr,  /* Filled with token for dynamically loaded
06609                                  * file which will be passed back to
06610                                  * (*unloadProcPtr)() to unload the file. */
06611     Tcl_FSUnloadFileProc **unloadProcPtr)
06612                                 /* Filled with address of Tcl_FSUnloadFileProc
06613                                  * function which should be used for
06614                                  * this file. */
06615 {
06616     TestReport("loadfile", fileName, NULL);
06617     return Tcl_FSLoadFile(interp, TestReportGetNativePath(fileName), NULL,
06618             NULL, NULL, NULL, handlePtr, unloadProcPtr);
06619 }
06620 
06621 static Tcl_Obj *
06622 TestReportLink(
06623     Tcl_Obj *path,              /* Path of file to readlink or link */
06624     Tcl_Obj *to,                /* Path of file to link to, or NULL */
06625     int linkType)
06626 {
06627     TestReport("link", path, to);
06628     return Tcl_FSLink(TestReportGetNativePath(path), to, linkType);
06629 }
06630 
06631 static int
06632 TestReportRenameFile(
06633     Tcl_Obj *src,               /* Pathname of file or dir to be renamed
06634                                  * (UTF-8). */
06635     Tcl_Obj *dst)               /* New pathname of file or directory
06636                                  * (UTF-8). */
06637 {
06638     TestReport("renamefile", src, dst);
06639     return Tcl_FSRenameFile(TestReportGetNativePath(src),
06640             TestReportGetNativePath(dst));
06641 }
06642 
06643 static int
06644 TestReportCopyFile(
06645     Tcl_Obj *src,               /* Pathname of file to be copied (UTF-8). */
06646     Tcl_Obj *dst)               /* Pathname of file to copy to (UTF-8). */
06647 {
06648     TestReport("copyfile", src, dst);
06649     return Tcl_FSCopyFile(TestReportGetNativePath(src),
06650             TestReportGetNativePath(dst));
06651 }
06652 
06653 static int
06654 TestReportDeleteFile(
06655     Tcl_Obj *path)              /* Pathname of file to be removed (UTF-8). */
06656 {
06657     TestReport("deletefile", path, NULL);
06658     return Tcl_FSDeleteFile(TestReportGetNativePath(path));
06659 }
06660 
06661 static int
06662 TestReportCreateDirectory(
06663     Tcl_Obj *path)              /* Pathname of directory to create (UTF-8). */
06664 {
06665     TestReport("createdirectory", path, NULL);
06666     return Tcl_FSCreateDirectory(TestReportGetNativePath(path));
06667 }
06668 
06669 static int
06670 TestReportCopyDirectory(
06671     Tcl_Obj *src,               /* Pathname of directory to be copied
06672                                  * (UTF-8). */
06673     Tcl_Obj *dst,               /* Pathname of target directory (UTF-8). */
06674     Tcl_Obj **errorPtr)         /* If non-NULL, to be filled with UTF-8 name
06675                                  * of file causing error. */
06676 {
06677     TestReport("copydirectory", src, dst);
06678     return Tcl_FSCopyDirectory(TestReportGetNativePath(src),
06679             TestReportGetNativePath(dst), errorPtr);
06680 }
06681 
06682 static int
06683 TestReportRemoveDirectory(
06684     Tcl_Obj *path,              /* Pathname of directory to be removed
06685                                  * (UTF-8). */
06686     int recursive,              /* If non-zero, removes directories that
06687                                  * are nonempty.  Otherwise, will only remove
06688                                  * empty directories. */
06689     Tcl_Obj **errorPtr)         /* If non-NULL, to be filled with UTF-8 name
06690                                  * of file causing error. */
06691 {
06692     TestReport("removedirectory", path, NULL);
06693     return Tcl_FSRemoveDirectory(TestReportGetNativePath(path), recursive,
06694             errorPtr);
06695 }
06696 
06697 static const char **
06698 TestReportFileAttrStrings(
06699     Tcl_Obj *fileName,
06700     Tcl_Obj **objPtrRef)
06701 {
06702     TestReport("fileattributestrings", fileName, NULL);
06703     return Tcl_FSFileAttrStrings(TestReportGetNativePath(fileName), objPtrRef);
06704 }
06705 
06706 static int
06707 TestReportFileAttrsGet(
06708     Tcl_Interp *interp,         /* The interpreter for error reporting. */
06709     int index,                  /* index of the attribute command. */
06710     Tcl_Obj *fileName,          /* filename we are operating on. */
06711     Tcl_Obj **objPtrRef)        /* for output. */
06712 {
06713     TestReport("fileattributesget", fileName, NULL);
06714     return Tcl_FSFileAttrsGet(interp, index,
06715             TestReportGetNativePath(fileName), objPtrRef);
06716 }
06717 
06718 static int
06719 TestReportFileAttrsSet(
06720     Tcl_Interp *interp,         /* The interpreter for error reporting. */
06721     int index,                  /* index of the attribute command. */
06722     Tcl_Obj *fileName,          /* filename we are operating on. */
06723     Tcl_Obj *objPtr)            /* for input. */
06724 {
06725     TestReport("fileattributesset", fileName, objPtr);
06726     return Tcl_FSFileAttrsSet(interp, index,
06727             TestReportGetNativePath(fileName), objPtr);
06728 }
06729 
06730 static int
06731 TestReportUtime(
06732     Tcl_Obj *fileName,
06733     struct utimbuf *tval)
06734 {
06735     TestReport("utime", fileName, NULL);
06736     return Tcl_FSUtime(TestReportGetNativePath(fileName), tval);
06737 }
06738 
06739 static int
06740 TestReportNormalizePath(
06741     Tcl_Interp *interp,
06742     Tcl_Obj *pathPtr,
06743     int nextCheckpoint)
06744 {
06745     TestReport("normalizepath", pathPtr, NULL);
06746     return nextCheckpoint;
06747 }
06748 
06749 static int
06750 SimplePathInFilesystem(
06751     Tcl_Obj *pathPtr,
06752     ClientData *clientDataPtr)
06753 {
06754     const char *str = Tcl_GetString(pathPtr);
06755 
06756     if (strncmp(str, "simplefs:/", 10)) {
06757         return -1;
06758     }
06759     return TCL_OK;
06760 }
06761 
06762 /*
06763  * This is a slightly 'hacky' filesystem which is used just to test a few
06764  * important features of the vfs code: (1) that you can load a shared library
06765  * from a vfs, (2) that when copying files from one fs to another, the 'mtime'
06766  * is preserved. (3) that recursive cross-filesystem directory copies have the
06767  * correct behaviour with/without -force.
06768  *
06769  * It treats any file in 'simplefs:/' as a file, which it routes to the
06770  * current directory. The real file it uses is whatever follows the trailing
06771  * '/' (e.g. 'foo' in 'simplefs:/foo'), and that file exists or not according
06772  * to what is in the native pwd.
06773  *
06774  * Please do not consider this filesystem a model of how things are to be
06775  * done. It is quite the opposite!  But, it does allow us to test some
06776  * important features.
06777  */
06778 
06779 static int
06780 TestSimpleFilesystemObjCmd(
06781     ClientData dummy,
06782     Tcl_Interp *interp,
06783     int objc,
06784     Tcl_Obj *const objv[])
06785 {
06786     int res, boolVal;
06787     char *msg;
06788 
06789     if (objc != 2) {
06790         Tcl_WrongNumArgs(interp, 1, objv, "boolean");
06791         return TCL_ERROR;
06792     }
06793     if (Tcl_GetBooleanFromObj(interp, objv[1], &boolVal) != TCL_OK) {
06794         return TCL_ERROR;
06795     }
06796     if (boolVal) {
06797         res = Tcl_FSRegister((ClientData)interp, &simpleFilesystem);
06798         msg = (res == TCL_OK) ? "registered" : "failed";
06799     } else {
06800         res = Tcl_FSUnregister(&simpleFilesystem);
06801         msg = (res == TCL_OK) ? "unregistered" : "failed";
06802     }
06803     Tcl_SetResult(interp, msg, TCL_VOLATILE);
06804     return res;
06805 }
06806 
06807 /*
06808  * Treats a file name 'simplefs:/foo' by using the file 'foo' in the current
06809  * (native) directory.
06810  */
06811 
06812 static Tcl_Obj *
06813 SimpleRedirect(
06814     Tcl_Obj *pathPtr)           /* Name of file to copy. */
06815 {
06816     int len;
06817     const char *str;
06818     Tcl_Obj *origPtr;
06819 
06820     /*
06821      * We assume the same name in the current directory is ok.
06822      */
06823 
06824     str = Tcl_GetStringFromObj(pathPtr, &len);
06825     if (len < 10 || strncmp(str, "simplefs:/", 10)) {
06826         /* Probably shouldn't ever reach here */
06827         Tcl_IncrRefCount(pathPtr);
06828         return pathPtr;
06829     }
06830     origPtr = Tcl_NewStringObj(str+10,-1);
06831     Tcl_IncrRefCount(origPtr);
06832     return origPtr;
06833 }
06834 
06835 static int
06836 SimpleMatchInDirectory(
06837     Tcl_Interp *interp,         /* Interpreter for error
06838                                  * messages. */
06839     Tcl_Obj *resultPtr,         /* Object to lappend results. */
06840     Tcl_Obj *dirPtr,            /* Contains path to directory to search. */
06841     const char *pattern,        /* Pattern to match against. */
06842     Tcl_GlobTypeData *types)    /* Object containing list of acceptable types.
06843                                  * May be NULL. */
06844 {
06845     int res;
06846     Tcl_Obj *origPtr;
06847     Tcl_Obj *resPtr;
06848 
06849     /* We only provide a new volume, therefore no mounts at all */
06850     if (types != NULL && types->type & TCL_GLOB_TYPE_MOUNT) {
06851         return TCL_OK;
06852     }
06853 
06854     /*
06855      * We assume the same name in the current directory is ok.
06856      */
06857     resPtr = Tcl_NewObj();
06858     Tcl_IncrRefCount(resPtr);
06859     origPtr = SimpleRedirect(dirPtr);
06860     res = Tcl_FSMatchInDirectory(interp, resPtr, origPtr, pattern, types);
06861     if (res == TCL_OK) {
06862         int gLength, j;
06863         Tcl_ListObjLength(NULL, resPtr, &gLength);
06864         for (j = 0; j < gLength; j++) {
06865             Tcl_Obj *gElt, *nElt;
06866             Tcl_ListObjIndex(NULL, resPtr, j, &gElt);
06867             nElt = Tcl_NewStringObj("simplefs:/",10);
06868             Tcl_AppendObjToObj(nElt, gElt);
06869             Tcl_ListObjAppendElement(NULL, resultPtr, nElt);
06870         }
06871     }
06872     Tcl_DecrRefCount(origPtr);
06873     Tcl_DecrRefCount(resPtr);
06874     return res;
06875 }
06876 
06877 static Tcl_Channel
06878 SimpleOpenFileChannel(
06879     Tcl_Interp *interp,         /* Interpreter for error reporting; can be
06880                                  * NULL. */
06881     Tcl_Obj *pathPtr,           /* Name of file to open. */
06882     int mode,                   /* POSIX open mode. */
06883     int permissions)            /* If the open involves creating a file, with
06884                                  * what modes to create it? */
06885 {
06886     Tcl_Obj *tempPtr;
06887     Tcl_Channel chan;
06888 
06889     if ((mode != 0) && !(mode & O_RDONLY)) {
06890         Tcl_AppendResult(interp, "read-only", NULL);
06891         return NULL;
06892     }
06893 
06894     tempPtr = SimpleRedirect(pathPtr);
06895     chan = Tcl_FSOpenFileChannel(interp, tempPtr, "r", permissions);
06896     Tcl_DecrRefCount(tempPtr);
06897     return chan;
06898 }
06899 
06900 static int
06901 SimpleAccess(
06902     Tcl_Obj *pathPtr,           /* Path of file to access (in current CP). */
06903     int mode)                   /* Permission setting. */
06904 {
06905     Tcl_Obj *tempPtr = SimpleRedirect(pathPtr);
06906     int res = Tcl_FSAccess(tempPtr, mode);
06907 
06908     Tcl_DecrRefCount(tempPtr);
06909     return res;
06910 }
06911 
06912 static int
06913 SimpleStat(
06914     Tcl_Obj *pathPtr,           /* Path of file to stat (in current CP). */
06915     Tcl_StatBuf *bufPtr)        /* Filled with results of stat call. */
06916 {
06917     Tcl_Obj *tempPtr = SimpleRedirect(pathPtr);
06918     int res = Tcl_FSStat(tempPtr, bufPtr);
06919 
06920     Tcl_DecrRefCount(tempPtr);
06921     return res;
06922 }
06923 
06924 static Tcl_Obj *
06925 SimpleListVolumes(void)
06926 {
06927     /* Add one new volume */
06928     Tcl_Obj *retVal;
06929 
06930     retVal = Tcl_NewStringObj("simplefs:/", -1);
06931     Tcl_IncrRefCount(retVal);
06932     return retVal;
06933 }
06934 
06935 /*
06936  * Used to check correct string-length determining in Tcl_NumUtfChars
06937  */
06938 
06939 static int
06940 TestNumUtfCharsCmd(
06941     ClientData clientData,
06942     Tcl_Interp *interp,
06943     int objc,
06944     Tcl_Obj *const objv[])
06945 {
06946     if (objc > 1) {
06947         int len = -1;
06948 
06949         if (objc > 2) {
06950             (void) Tcl_GetStringFromObj(objv[1], &len);
06951         }
06952         len = Tcl_NumUtfChars(Tcl_GetString(objv[1]), len);
06953         Tcl_SetObjResult(interp, Tcl_NewIntObj(len));
06954     }
06955     return TCL_OK;
06956 }
06957 
06958 /*
06959  * Used to do basic checks of the TCL_HASH_KEY_SYSTEM_HASH flag
06960  */
06961 
06962 static int
06963 TestHashSystemHashCmd(
06964     ClientData clientData,
06965     Tcl_Interp *interp,
06966     int objc,
06967     Tcl_Obj *const objv[])
06968 {
06969     static Tcl_HashKeyType hkType = {
06970         TCL_HASH_KEY_TYPE_VERSION, TCL_HASH_KEY_SYSTEM_HASH,
06971         NULL, NULL, NULL, NULL
06972     };
06973     Tcl_HashTable hash;
06974     Tcl_HashEntry *hPtr;
06975     int i, isNew, limit = 100;
06976 
06977     if (objc>1 && Tcl_GetIntFromObj(interp, objv[1], &limit)!=TCL_OK) {
06978         return TCL_ERROR;
06979     }
06980 
06981     Tcl_InitCustomHashTable(&hash, TCL_CUSTOM_TYPE_KEYS, &hkType);
06982 
06983     if (hash.numEntries != 0) {
06984         Tcl_AppendResult(interp, "non-zero initial size", NULL);
06985         Tcl_DeleteHashTable(&hash);
06986         return TCL_ERROR;
06987     }
06988 
06989     for (i=0 ; i<limit ; i++) {
06990         hPtr = Tcl_CreateHashEntry(&hash, (char *) INT2PTR(i), &isNew);
06991         if (!isNew) {
06992             Tcl_SetObjResult(interp, Tcl_NewIntObj(i));
06993             Tcl_AppendToObj(Tcl_GetObjResult(interp)," creation problem",-1);
06994             Tcl_DeleteHashTable(&hash);
06995             return TCL_ERROR;
06996         }
06997         Tcl_SetHashValue(hPtr, (ClientData) INT2PTR(i+42));
06998     }
06999 
07000     if (hash.numEntries != limit) {
07001         Tcl_AppendResult(interp, "unexpected maximal size", NULL);
07002         Tcl_DeleteHashTable(&hash);
07003         return TCL_ERROR;
07004     }
07005 
07006     for (i=0 ; i<limit ; i++) {
07007         hPtr = Tcl_FindHashEntry(&hash, (char *) INT2PTR(i));
07008         if (hPtr == NULL) {
07009             Tcl_SetObjResult(interp, Tcl_NewIntObj(i));
07010             Tcl_AppendToObj(Tcl_GetObjResult(interp)," lookup problem",-1);
07011             Tcl_DeleteHashTable(&hash);
07012             return TCL_ERROR;
07013         }
07014         if (PTR2INT(Tcl_GetHashValue(hPtr)) != i+42) {
07015             Tcl_SetObjResult(interp, Tcl_NewIntObj(i));
07016             Tcl_AppendToObj(Tcl_GetObjResult(interp)," value problem",-1);
07017             Tcl_DeleteHashTable(&hash);
07018             return TCL_ERROR;
07019         }
07020         Tcl_DeleteHashEntry(hPtr);
07021     }
07022 
07023     if (hash.numEntries != 0) {
07024         Tcl_AppendResult(interp, "non-zero final size", NULL);
07025         Tcl_DeleteHashTable(&hash);
07026         return TCL_ERROR;
07027     }
07028 
07029     Tcl_DeleteHashTable(&hash);
07030     Tcl_AppendResult(interp, "OK", NULL);
07031     return TCL_OK;
07032 }
07033 
07034 /*
07035  * Used for testing Tcl_GetInt which is no longer used directly by the
07036  * core very much.
07037  */
07038 static int
07039 TestgetintCmd(
07040     ClientData dummy,
07041     Tcl_Interp *interp,
07042     int argc,
07043     const char **argv)
07044 {
07045     if (argc < 2) {
07046         Tcl_SetResult(interp, "wrong # args", TCL_STATIC);
07047         return TCL_ERROR;
07048     } else {
07049         int val, i, total=0;
07050         char buf[TCL_INTEGER_SPACE];
07051 
07052         for (i=1 ; i<argc ; i++) {
07053             if (Tcl_GetInt(interp, argv[i], &val) != TCL_OK) {
07054                 return TCL_ERROR;
07055             }
07056             total += val;
07057         }
07058         TclFormatInt(buf, total);
07059         Tcl_SetResult(interp, buf, TCL_VOLATILE);
07060         return TCL_OK;
07061     }
07062 }
07063 
07064 /*
07065  * Local Variables:
07066  * mode: c
07067  * c-basic-offset: 4
07068  * fill-column: 78
07069  * End:
07070  */



Generated on Wed Mar 12 12:18:22 2008 by  doxygen 1.5.1