tclTest.cGo 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®_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®_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 1.5.1 |