os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/unix/tclUnixTest.c
First public contribution.
4 * Contains platform specific test commands for the Unix platform.
6 * Copyright (c) 1996-1997 Sun Microsystems, Inc.
7 * Copyright (c) 1998 by Scriptics Corporation.
8 * Portions Copyright (c) 2007 Nokia Corporation and/or its subsidiaries. All rights reserved.
10 * See the file "license.terms" for information on usage and redistribution
11 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13 * RCS: @(#) $Id: tclUnixTest.c,v 1.14.2.2 2006/03/19 22:47:30 vincentdarley Exp $
18 #if defined(__SYMBIAN32__)
19 #include "tclSymbianGlobals.h"
23 * The headers are needed for the testalarm command that verifies the
24 * use of SA_RESTART in signal handlers.
30 #include <sys/resource.h>
33 * The following macros convert between TclFile's and fd's. The conversion
34 * simple involves shifting fd's up by one to ensure that no valid fd is ever
35 * the same as NULL. Note that this code is duplicated from tclUnixPipe.c
38 #define MakeFile(fd) ((TclFile)((fd)+1))
39 #define GetFd(file) (((int)file)-1)
42 * The stuff below is used to keep track of file handlers created and
43 * exercised by the "testfilehandler" command.
47 TclFile readFile; /* File handle for reading from the
48 * pipe. NULL means pipe doesn't exist yet. */
49 TclFile writeFile; /* File handle for writing from the
51 int readCount; /* Number of times the file handler for
52 * this file has triggered and the file
54 int writeCount; /* Number of times the file handler for
55 * this file has triggered and the file
60 static Pipe testPipes[MAX_PIPES];
63 * The stuff below is used by the testalarm and testgotsig ommands.
66 static char *gotsig = "0";
69 * Forward declarations of procedures defined later in this file:
72 static void TestFileHandlerProc _ANSI_ARGS_((ClientData clientData,
74 static int TestfilehandlerCmd _ANSI_ARGS_((ClientData dummy,
75 Tcl_Interp *interp, int argc, CONST char **argv));
76 static int TestfilewaitCmd _ANSI_ARGS_((ClientData dummy,
77 Tcl_Interp *interp, int argc, CONST char **argv));
78 static int TestfindexecutableCmd _ANSI_ARGS_((ClientData dummy,
79 Tcl_Interp *interp, int argc, CONST char **argv));
80 static int TestgetopenfileCmd _ANSI_ARGS_((ClientData dummy,
81 Tcl_Interp *interp, int argc, CONST char **argv));
82 static int TestgetdefencdirCmd _ANSI_ARGS_((ClientData dummy,
83 Tcl_Interp *interp, int argc, CONST char **argv));
84 static int TestsetdefencdirCmd _ANSI_ARGS_((ClientData dummy,
85 Tcl_Interp *interp, int argc, CONST char **argv));
86 int TclplatformtestInit _ANSI_ARGS_((Tcl_Interp *interp));
87 static int TestalarmCmd _ANSI_ARGS_((ClientData dummy,
88 Tcl_Interp *interp, int argc, CONST char **argv));
89 static int TestgotsigCmd _ANSI_ARGS_((ClientData dummy,
90 Tcl_Interp *interp, int argc, CONST char **argv));
91 static void AlarmHandler _ANSI_ARGS_(());
92 static int TestchmodCmd _ANSI_ARGS_((ClientData dummy,
93 Tcl_Interp *interp, int argc, CONST char **argv));
96 *----------------------------------------------------------------------
98 * TclplatformtestInit --
100 * Defines commands that test platform specific functionality for
104 * A standard Tcl result.
107 * Defines new commands.
109 *----------------------------------------------------------------------
113 TclplatformtestInit(interp)
114 Tcl_Interp *interp; /* Interpreter to add commands to. */
116 Tcl_CreateCommand(interp, "testchmod", TestchmodCmd,
117 (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
118 Tcl_CreateCommand(interp, "testfilehandler", TestfilehandlerCmd,
119 (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
120 Tcl_CreateCommand(interp, "testfilewait", TestfilewaitCmd,
121 (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
122 Tcl_CreateCommand(interp, "testfindexecutable", TestfindexecutableCmd,
123 (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
124 Tcl_CreateCommand(interp, "testgetopenfile", TestgetopenfileCmd,
125 (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
126 Tcl_CreateCommand(interp, "testgetdefenc", TestgetdefencdirCmd,
127 (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
128 Tcl_CreateCommand(interp, "testsetdefenc", TestsetdefencdirCmd,
129 (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
130 #ifndef __SYMBIAN32__
131 // Symbian and PIPS don't support signals.
132 Tcl_CreateCommand(interp, "testalarm", TestalarmCmd,
133 (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
135 Tcl_CreateCommand(interp, "testgotsig", TestgotsigCmd,
136 (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
141 *----------------------------------------------------------------------
143 * TestfilehandlerCmd --
145 * This procedure implements the "testfilehandler" command. It is
146 * used to test Tcl_CreateFileHandler, Tcl_DeleteFileHandler, and
150 * A standard Tcl result.
155 *----------------------------------------------------------------------
159 TestfilehandlerCmd(clientData, interp, argc, argv)
160 ClientData clientData; /* Not used. */
161 Tcl_Interp *interp; /* Current interpreter. */
162 int argc; /* Number of arguments. */
163 CONST char **argv; /* Argument strings. */
166 int i, mask, timeout;
167 static int initialized = 0;
172 * NOTE: When we make this code work on Windows also, the following
173 * variable needs to be made Unix-only.
177 for (i = 0; i < MAX_PIPES; i++) {
178 testPipes[i].readFile = NULL;
184 Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0],
185 " option ... \"", (char *) NULL);
190 if (Tcl_GetInt(interp, argv[2], &i) != TCL_OK) {
193 if (i >= MAX_PIPES) {
194 Tcl_AppendResult(interp, "bad index ", argv[2], (char *) NULL);
197 pipePtr = &testPipes[i];
200 if (strcmp(argv[1], "close") == 0) {
201 for (i = 0; i < MAX_PIPES; i++) {
202 if (testPipes[i].readFile != NULL) {
203 TclpCloseFile(testPipes[i].readFile);
204 testPipes[i].readFile = NULL;
205 TclpCloseFile(testPipes[i].writeFile);
206 testPipes[i].writeFile = NULL;
209 } else if (strcmp(argv[1], "clear") == 0) {
211 Tcl_AppendResult(interp, "wrong # arguments: should be \"",
212 argv[0], " clear index\"", (char *) NULL);
215 pipePtr->readCount = pipePtr->writeCount = 0;
216 } else if (strcmp(argv[1], "counts") == 0) {
217 char buf[TCL_INTEGER_SPACE * 2];
220 Tcl_AppendResult(interp, "wrong # arguments: should be \"",
221 argv[0], " counts index\"", (char *) NULL);
224 sprintf(buf, "%d %d", pipePtr->readCount, pipePtr->writeCount);
225 Tcl_SetResult(interp, buf, TCL_VOLATILE);
226 } else if (strcmp(argv[1], "create") == 0) {
228 Tcl_AppendResult(interp, "wrong # arguments: should be \"",
229 argv[0], " create index readMode writeMode\"",
233 if (pipePtr->readFile == NULL) {
234 if (!TclpCreatePipe(&pipePtr->readFile, &pipePtr->writeFile)) {
235 Tcl_AppendResult(interp, "couldn't open pipe: ",
236 Tcl_PosixError(interp), (char *) NULL);
240 fcntl(GetFd(pipePtr->readFile), F_SETFL, O_NONBLOCK);
241 fcntl(GetFd(pipePtr->writeFile), F_SETFL, O_NONBLOCK);
243 Tcl_SetResult(interp, "can't make pipes non-blocking",
248 pipePtr->readCount = 0;
249 pipePtr->writeCount = 0;
251 if (strcmp(argv[3], "readable") == 0) {
252 Tcl_CreateFileHandler(GetFd(pipePtr->readFile), TCL_READABLE,
253 TestFileHandlerProc, (ClientData) pipePtr);
254 } else if (strcmp(argv[3], "off") == 0) {
255 Tcl_DeleteFileHandler(GetFd(pipePtr->readFile));
256 } else if (strcmp(argv[3], "disabled") == 0) {
257 Tcl_CreateFileHandler(GetFd(pipePtr->readFile), 0,
258 TestFileHandlerProc, (ClientData) pipePtr);
260 Tcl_AppendResult(interp, "bad read mode \"", argv[3], "\"",
264 if (strcmp(argv[4], "writable") == 0) {
265 Tcl_CreateFileHandler(GetFd(pipePtr->writeFile), TCL_WRITABLE,
266 TestFileHandlerProc, (ClientData) pipePtr);
267 } else if (strcmp(argv[4], "off") == 0) {
268 Tcl_DeleteFileHandler(GetFd(pipePtr->writeFile));
269 } else if (strcmp(argv[4], "disabled") == 0) {
270 Tcl_CreateFileHandler(GetFd(pipePtr->writeFile), 0,
271 TestFileHandlerProc, (ClientData) pipePtr);
273 Tcl_AppendResult(interp, "bad read mode \"", argv[4], "\"",
277 } else if (strcmp(argv[1], "empty") == 0) {
279 Tcl_AppendResult(interp, "wrong # arguments: should be \"",
280 argv[0], " empty index\"", (char *) NULL);
284 while (read(GetFd(pipePtr->readFile), buffer, 4000) > 0) {
285 /* Empty loop body. */
287 } else if (strcmp(argv[1], "fill") == 0) {
289 Tcl_AppendResult(interp, "wrong # arguments: should be \"",
290 argv[0], " fill index\"", (char *) NULL);
294 memset((VOID *) buffer, 'a', 4000);
295 while (write(GetFd(pipePtr->writeFile), buffer, 4000) > 0) {
296 /* Empty loop body. */
298 } else if (strcmp(argv[1], "fillpartial") == 0) {
299 char buf[TCL_INTEGER_SPACE];
302 Tcl_AppendResult(interp, "wrong # arguments: should be \"",
303 argv[0], " fillpartial index\"", (char *) NULL);
307 memset((VOID *) buffer, 'b', 10);
308 TclFormatInt(buf, write(GetFd(pipePtr->writeFile), buffer, 10));
309 Tcl_SetResult(interp, buf, TCL_VOLATILE);
310 } else if (strcmp(argv[1], "oneevent") == 0) {
311 Tcl_DoOneEvent(TCL_FILE_EVENTS|TCL_DONT_WAIT);
312 } else if (strcmp(argv[1], "wait") == 0) {
314 Tcl_AppendResult(interp, "wrong # arguments: should be \"",
315 argv[0], " wait index readable|writable timeout\"",
319 if (pipePtr->readFile == NULL) {
320 Tcl_AppendResult(interp, "pipe ", argv[2], " doesn't exist",
324 if (strcmp(argv[3], "readable") == 0) {
326 file = pipePtr->readFile;
329 file = pipePtr->writeFile;
331 if (Tcl_GetInt(interp, argv[4], &timeout) != TCL_OK) {
334 i = TclUnixWaitForFile(GetFd(file), mask, timeout);
335 if (i & TCL_READABLE) {
336 Tcl_AppendElement(interp, "readable");
338 if (i & TCL_WRITABLE) {
339 Tcl_AppendElement(interp, "writable");
341 } else if (strcmp(argv[1], "windowevent") == 0) {
342 Tcl_DoOneEvent(TCL_WINDOW_EVENTS|TCL_DONT_WAIT);
344 Tcl_AppendResult(interp, "bad option \"", argv[1],
345 "\": must be close, clear, counts, create, empty, fill, ",
346 "fillpartial, oneevent, wait, or windowevent",
353 static void TestFileHandlerProc(clientData, mask)
354 ClientData clientData; /* Points to a Pipe structure. */
355 int mask; /* Indicates which events happened:
356 * TCL_READABLE or TCL_WRITABLE. */
358 Pipe *pipePtr = (Pipe *) clientData;
360 if (mask & TCL_READABLE) {
361 pipePtr->readCount++;
363 if (mask & TCL_WRITABLE) {
364 pipePtr->writeCount++;
369 *----------------------------------------------------------------------
373 * This procedure implements the "testfilewait" command. It is
374 * used to test TclUnixWaitForFile.
377 * A standard Tcl result.
382 *----------------------------------------------------------------------
386 TestfilewaitCmd(clientData, interp, argc, argv)
387 ClientData clientData; /* Not used. */
388 Tcl_Interp *interp; /* Current interpreter. */
389 int argc; /* Number of arguments. */
390 CONST char **argv; /* Argument strings. */
392 int mask, result, timeout;
398 Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0],
399 " file readable|writable|both timeout\"", (char *) NULL);
402 channel = Tcl_GetChannel(interp, argv[1], NULL);
403 if (channel == NULL) {
406 if (strcmp(argv[2], "readable") == 0) {
408 } else if (strcmp(argv[2], "writable") == 0){
410 } else if (strcmp(argv[2], "both") == 0){
411 mask = TCL_WRITABLE|TCL_READABLE;
413 Tcl_AppendResult(interp, "bad argument \"", argv[2],
414 "\": must be readable, writable, or both", (char *) NULL);
417 if (Tcl_GetChannelHandle(channel,
418 (mask & TCL_READABLE) ? TCL_READABLE : TCL_WRITABLE,
419 (ClientData*) &data) != TCL_OK) {
420 Tcl_SetResult(interp, "couldn't get channel file", TCL_STATIC);
424 if (Tcl_GetInt(interp, argv[3], &timeout) != TCL_OK) {
427 result = TclUnixWaitForFile(fd, mask, timeout);
428 if (result & TCL_READABLE) {
429 Tcl_AppendElement(interp, "readable");
431 if (result & TCL_WRITABLE) {
432 Tcl_AppendElement(interp, "writable");
438 *----------------------------------------------------------------------
440 * TestfindexecutableCmd --
442 * This procedure implements the "testfindexecutable" command. It is
443 * used to test Tcl_FindExecutable.
446 * A standard Tcl result.
451 *----------------------------------------------------------------------
455 TestfindexecutableCmd(clientData, interp, argc, argv)
456 ClientData clientData; /* Not used. */
457 Tcl_Interp *interp; /* Current interpreter. */
458 int argc; /* Number of arguments. */
459 CONST char **argv; /* Argument strings. */
465 Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0],
466 " argv0\"", (char *) NULL);
470 oldName = tclExecutableName;
471 oldNativeName = tclNativeExecutableName;
473 tclExecutableName = NULL;
474 tclNativeExecutableName = NULL;
476 Tcl_FindExecutable(argv[1]);
477 if (tclExecutableName != NULL) {
478 Tcl_SetResult(interp, tclExecutableName, TCL_VOLATILE);
479 ckfree(tclExecutableName);
481 if (tclNativeExecutableName != NULL) {
482 ckfree(tclNativeExecutableName);
485 tclExecutableName = oldName;
486 tclNativeExecutableName = oldNativeName;
492 *----------------------------------------------------------------------
494 * TestgetopenfileCmd --
496 * This procedure implements the "testgetopenfile" command. It is
497 * used to get a FILE * value from a registered channel.
500 * A standard Tcl result.
505 *----------------------------------------------------------------------
509 TestgetopenfileCmd(clientData, interp, argc, argv)
510 ClientData clientData; /* Not used. */
511 Tcl_Interp *interp; /* Current interpreter. */
512 int argc; /* Number of arguments. */
513 CONST char **argv; /* Argument strings. */
518 Tcl_AppendResult(interp,
519 "wrong # args: should be \"", argv[0],
520 " channelName forWriting\"",
524 if (Tcl_GetOpenFile(interp, argv[1], atoi(argv[2]), 1, &filePtr)
528 if (filePtr == (ClientData) NULL) {
529 Tcl_AppendResult(interp,
530 "Tcl_GetOpenFile succeeded but FILE * NULL!", (char *) NULL);
537 *----------------------------------------------------------------------
539 * TestsetdefencdirCmd --
541 * This procedure implements the "testsetdefenc" command. It is
542 * used to set the value of tclDefaultEncodingDir.
545 * A standard Tcl result.
550 *----------------------------------------------------------------------
554 TestsetdefencdirCmd(clientData, interp, argc, argv)
555 ClientData clientData; /* Not used. */
556 Tcl_Interp *interp; /* Current interpreter. */
557 int argc; /* Number of arguments. */
558 CONST char **argv; /* Argument strings. */
561 Tcl_AppendResult(interp,
562 "wrong # args: should be \"", argv[0],
568 if (tclDefaultEncodingDir != NULL) {
569 ckfree(tclDefaultEncodingDir);
570 tclDefaultEncodingDir = NULL;
572 if (*argv[1] != '\0') {
573 tclDefaultEncodingDir = (char *)
574 ckalloc((unsigned) strlen(argv[1]) + 1);
575 strcpy(tclDefaultEncodingDir, argv[1]);
581 *----------------------------------------------------------------------
583 * TestgetdefencdirCmd --
585 * This procedure implements the "testgetdefenc" command. It is
586 * used to get the value of tclDefaultEncodingDir.
589 * A standard Tcl result.
594 *----------------------------------------------------------------------
598 TestgetdefencdirCmd(clientData, interp, argc, argv)
599 ClientData clientData; /* Not used. */
600 Tcl_Interp *interp; /* Current interpreter. */
601 int argc; /* Number of arguments. */
602 CONST char **argv; /* Argument strings. */
605 Tcl_AppendResult(interp,
606 "wrong # args: should be \"", argv[0],
611 if (tclDefaultEncodingDir != NULL) {
612 Tcl_AppendResult(interp, tclDefaultEncodingDir, (char *) NULL);
618 *----------------------------------------------------------------------
621 * Test that EINTR is handled correctly by generating and
622 * handling a signal. This requires using the SA_RESTART
623 * flag when registering the signal handler.
629 * Sets up an signal and async handlers.
631 *----------------------------------------------------------------------
635 TestalarmCmd(clientData, interp, argc, argv)
636 ClientData clientData; /* Not used. */
637 Tcl_Interp *interp; /* Current interpreter. */
638 int argc; /* Number of arguments. */
639 CONST char **argv; /* Argument strings. */
643 struct sigaction action;
646 Tcl_GetInt(interp, argv[1], (int *)&sec);
652 * Setup the signal handling that automatically retries
653 * any interupted I/O system calls.
655 action.sa_handler = AlarmHandler;
656 memset((void *)&action.sa_mask, 0, sizeof(sigset_t));
657 action.sa_flags = SA_RESTART;
659 if (sigaction(SIGALRM, &action, NULL) < 0) {
660 Tcl_AppendResult(interp, "sigaction: ", Tcl_PosixError(interp), NULL);
666 Tcl_AppendResult(interp, "warning: sigaction SA_RESTART not support on this platform", NULL);
672 *----------------------------------------------------------------------
676 * Signal handler for the alarm command.
682 * Calls the Tcl Async handler.
684 *----------------------------------------------------------------------
694 *----------------------------------------------------------------------
697 * Verify the signal was handled after the testalarm command.
703 * Resets the value of gotsig back to '0'.
705 *----------------------------------------------------------------------
709 TestgotsigCmd(clientData, interp, argc, argv)
710 ClientData clientData; /* Not used. */
711 Tcl_Interp *interp; /* Current interpreter. */
712 int argc; /* Number of arguments. */
713 CONST char **argv; /* Argument strings. */
715 Tcl_AppendResult(interp, gotsig, (char *) NULL);
721 *---------------------------------------------------------------------------
725 * Implements the "testchmod" cmd. Used when testing "file" command.
726 * The only attribute used by the Windows platform is the user write
727 * flag; if this is not set, the file is made read-only. Otehrwise, the
728 * file is made read-write.
731 * A standard Tcl result.
734 * Changes permissions of specified files.
736 *---------------------------------------------------------------------------
740 TestchmodCmd(dummy, interp, argc, argv)
741 ClientData dummy; /* Not used. */
742 Tcl_Interp *interp; /* Current interpreter. */
743 int argc; /* Number of arguments. */
744 CONST char **argv; /* Argument strings. */
751 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
752 " mode file ?file ...?", NULL);
756 mode = (int) strtol(argv[1], &rest, 8);
757 if ((rest == argv[1]) || (*rest != '\0')) {
761 for (i = 2; i < argc; i++) {
763 CONST char *translated;
765 translated = Tcl_TranslateFileName(interp, argv[i], &buffer);
766 if (translated == NULL) {
769 if (chmod(translated, (unsigned) mode) != 0) {
770 Tcl_AppendResult(interp, translated, ": ", Tcl_PosixError(interp),
774 Tcl_DStringFree(&buffer);