os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/unix/tclUnixTest.c
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 /* 
     2  * tclUnixTest.c --
     3  *
     4  *	Contains platform specific test commands for the Unix platform.
     5  *
     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.   
     9  *
    10  * See the file "license.terms" for information on usage and redistribution
    11  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
    12  *
    13  * RCS: @(#) $Id: tclUnixTest.c,v 1.14.2.2 2006/03/19 22:47:30 vincentdarley Exp $
    14  */
    15 
    16 #include "tclInt.h"
    17 #include "tclPort.h"
    18 #if defined(__SYMBIAN32__) 
    19 #include "tclSymbianGlobals.h"
    20 #endif 
    21 
    22 /*
    23  * The headers are needed for the testalarm command that verifies the
    24  * use of SA_RESTART in signal handlers.
    25  */
    26 
    27 #ifndef __SYMBIAN32__  
    28 #include <signal.h>
    29 #endif
    30 #include <sys/resource.h>
    31 
    32 /*
    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
    36  */
    37 
    38 #define MakeFile(fd) ((TclFile)((fd)+1))
    39 #define GetFd(file) (((int)file)-1)
    40 
    41 /*
    42  * The stuff below is used to keep track of file handlers created and
    43  * exercised by the "testfilehandler" command.
    44  */
    45 
    46 typedef struct Pipe {
    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
    50 				 * pipe. */
    51     int readCount;		/* Number of times the file handler for
    52 				 * this file has triggered and the file
    53 				 * was readable. */
    54     int writeCount;		/* Number of times the file handler for
    55 				 * this file has triggered and the file
    56 				 * was writable. */
    57 } Pipe;
    58 
    59 #define MAX_PIPES 10
    60 static Pipe testPipes[MAX_PIPES];
    61 
    62 /*
    63  * The stuff below is used by the testalarm and testgotsig ommands.
    64  */
    65 
    66 static char *gotsig = "0";
    67 
    68 /*
    69  * Forward declarations of procedures defined later in this file:
    70  */
    71 
    72 static void		TestFileHandlerProc _ANSI_ARGS_((ClientData clientData,
    73 			    int mask));
    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));
    94 
    95 /*
    96  *----------------------------------------------------------------------
    97  *
    98  * TclplatformtestInit --
    99  *
   100  *	Defines commands that test platform specific functionality for
   101  *	Unix platforms.
   102  *
   103  * Results:
   104  *	A standard Tcl result.
   105  *
   106  * Side effects:
   107  *	Defines new commands.
   108  *
   109  *----------------------------------------------------------------------
   110  */
   111 
   112 int
   113 TclplatformtestInit(interp)
   114     Tcl_Interp *interp;		/* Interpreter to add commands to. */
   115 {
   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);
   134 #endif
   135     Tcl_CreateCommand(interp, "testgotsig", TestgotsigCmd,
   136             (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
   137     return TCL_OK;
   138 }
   139 
   140 /*
   141  *----------------------------------------------------------------------
   142  *
   143  * TestfilehandlerCmd --
   144  *
   145  *	This procedure implements the "testfilehandler" command. It is
   146  *	used to test Tcl_CreateFileHandler, Tcl_DeleteFileHandler, and
   147  *	TclWaitForFile.
   148  *
   149  * Results:
   150  *	A standard Tcl result.
   151  *
   152  * Side effects:
   153  *	None.
   154  *
   155  *----------------------------------------------------------------------
   156  */
   157 
   158 static int
   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. */
   164 {
   165     Pipe *pipePtr;
   166     int i, mask, timeout;
   167     static int initialized = 0;
   168     char buffer[4000];
   169     TclFile file;
   170 
   171     /*
   172      * NOTE: When we make this code work on Windows also, the following
   173      * variable needs to be made Unix-only.
   174      */
   175     
   176     if (!initialized) {
   177 	for (i = 0; i < MAX_PIPES; i++) {
   178 	    testPipes[i].readFile = NULL;
   179 	}
   180 	initialized = 1;
   181     }
   182 
   183     if (argc < 2) {
   184 	Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0],
   185                 " option ... \"", (char *) NULL);
   186         return TCL_ERROR;
   187     }
   188     pipePtr = NULL;
   189     if (argc >= 3) {
   190 	if (Tcl_GetInt(interp, argv[2], &i) != TCL_OK) {
   191 	    return TCL_ERROR;
   192 	}
   193 	if (i >= MAX_PIPES) {
   194 	    Tcl_AppendResult(interp, "bad index ", argv[2], (char *) NULL);
   195 	    return TCL_ERROR;
   196 	}
   197 	pipePtr = &testPipes[i];
   198     }
   199 
   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;
   207 	    }
   208 	}
   209     } else if (strcmp(argv[1], "clear") == 0) {
   210 	if (argc != 3) {
   211 	    Tcl_AppendResult(interp, "wrong # arguments: should be \"",
   212                     argv[0], " clear index\"", (char *) NULL);
   213 	    return TCL_ERROR;
   214 	}
   215 	pipePtr->readCount = pipePtr->writeCount = 0;
   216     } else if (strcmp(argv[1], "counts") == 0) {
   217 	char buf[TCL_INTEGER_SPACE * 2];
   218 	
   219 	if (argc != 3) {
   220 	    Tcl_AppendResult(interp, "wrong # arguments: should be \"",
   221                     argv[0], " counts index\"", (char *) NULL);
   222 	    return TCL_ERROR;
   223 	}
   224 	sprintf(buf, "%d %d", pipePtr->readCount, pipePtr->writeCount);
   225 	Tcl_SetResult(interp, buf, TCL_VOLATILE);
   226     } else if (strcmp(argv[1], "create") == 0) {
   227 	if (argc != 5) {
   228 	    Tcl_AppendResult(interp, "wrong # arguments: should be \"",
   229                     argv[0], " create index readMode writeMode\"",
   230                     (char *) NULL);
   231 	    return TCL_ERROR;
   232 	}
   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);
   237 		return TCL_ERROR;
   238 	    }
   239 #ifdef O_NONBLOCK
   240 	    fcntl(GetFd(pipePtr->readFile), F_SETFL, O_NONBLOCK);
   241 	    fcntl(GetFd(pipePtr->writeFile), F_SETFL, O_NONBLOCK);
   242 #else
   243 	    Tcl_SetResult(interp, "can't make pipes non-blocking",
   244 		    TCL_STATIC);
   245 	    return TCL_ERROR;
   246 #endif
   247 	}
   248 	pipePtr->readCount = 0;
   249 	pipePtr->writeCount = 0;
   250 
   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);
   259 	} else {
   260 	    Tcl_AppendResult(interp, "bad read mode \"", argv[3], "\"",
   261 		    (char *) NULL);
   262 	    return TCL_ERROR;
   263 	}
   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);
   272 	} else {
   273 	    Tcl_AppendResult(interp, "bad read mode \"", argv[4], "\"",
   274 		    (char *) NULL);
   275 	    return TCL_ERROR;
   276 	}
   277     } else if (strcmp(argv[1], "empty") == 0) {
   278 	if (argc != 3) {
   279 	    Tcl_AppendResult(interp, "wrong # arguments: should be \"",
   280                     argv[0], " empty index\"", (char *) NULL);
   281 	    return TCL_ERROR;
   282 	}
   283 
   284         while (read(GetFd(pipePtr->readFile), buffer, 4000) > 0) {
   285             /* Empty loop body. */
   286         }
   287     } else if (strcmp(argv[1], "fill") == 0) {
   288 	if (argc != 3) {
   289 	    Tcl_AppendResult(interp, "wrong # arguments: should be \"",
   290                     argv[0], " fill index\"", (char *) NULL);
   291 	    return TCL_ERROR;
   292 	}
   293 
   294 	memset((VOID *) buffer, 'a', 4000);
   295         while (write(GetFd(pipePtr->writeFile), buffer, 4000) > 0) {
   296             /* Empty loop body. */
   297         }
   298     } else if (strcmp(argv[1], "fillpartial") == 0) {
   299 	char buf[TCL_INTEGER_SPACE];
   300 	
   301 	if (argc != 3) {
   302 	    Tcl_AppendResult(interp, "wrong # arguments: should be \"",
   303                     argv[0], " fillpartial index\"", (char *) NULL);
   304 	    return TCL_ERROR;
   305 	}
   306 
   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) {
   313 	if (argc != 5) {
   314 	    Tcl_AppendResult(interp, "wrong # arguments: should be \"",
   315                     argv[0], " wait index readable|writable timeout\"",
   316                     (char *) NULL);
   317 	    return TCL_ERROR;
   318 	}
   319 	if (pipePtr->readFile == NULL) {
   320 	    Tcl_AppendResult(interp, "pipe ", argv[2], " doesn't exist",
   321 		    (char *) NULL);
   322 	    return TCL_ERROR;
   323 	}
   324 	if (strcmp(argv[3], "readable") == 0) {
   325 	    mask = TCL_READABLE;
   326 	    file = pipePtr->readFile;
   327 	} else {
   328 	    mask = TCL_WRITABLE;
   329 	    file = pipePtr->writeFile;
   330 	}
   331 	if (Tcl_GetInt(interp, argv[4], &timeout) != TCL_OK) {
   332 	    return TCL_ERROR;
   333 	}
   334 	i = TclUnixWaitForFile(GetFd(file), mask, timeout);
   335 	if (i & TCL_READABLE) {
   336 	    Tcl_AppendElement(interp, "readable");
   337 	}
   338 	if (i & TCL_WRITABLE) {
   339 	    Tcl_AppendElement(interp, "writable");
   340 	}
   341     } else if (strcmp(argv[1], "windowevent") == 0) {
   342 	Tcl_DoOneEvent(TCL_WINDOW_EVENTS|TCL_DONT_WAIT);
   343     } else {
   344 	Tcl_AppendResult(interp, "bad option \"", argv[1],
   345 		"\": must be close, clear, counts, create, empty, fill, ",
   346 		"fillpartial, oneevent, wait, or windowevent",
   347 		(char *) NULL);
   348 	return TCL_ERROR;
   349     }
   350     return TCL_OK;
   351 }
   352 
   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. */
   357 {
   358     Pipe *pipePtr = (Pipe *) clientData;
   359 
   360     if (mask & TCL_READABLE) {
   361 	pipePtr->readCount++;
   362     }
   363     if (mask & TCL_WRITABLE) {
   364 	pipePtr->writeCount++;
   365     }
   366 }
   367 
   368 /*
   369  *----------------------------------------------------------------------
   370  *
   371  * TestfilewaitCmd --
   372  *
   373  *	This procedure implements the "testfilewait" command. It is
   374  *	used to test TclUnixWaitForFile.
   375  *
   376  * Results:
   377  *	A standard Tcl result.
   378  *
   379  * Side effects:
   380  *	None.
   381  *
   382  *----------------------------------------------------------------------
   383  */
   384 
   385 static int
   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. */
   391 {
   392     int mask, result, timeout;
   393     Tcl_Channel channel;
   394     int fd;
   395     ClientData data;
   396 
   397     if (argc != 4) {
   398 	Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0],
   399 		" file readable|writable|both timeout\"", (char *) NULL);
   400 	return TCL_ERROR;
   401     }
   402     channel = Tcl_GetChannel(interp, argv[1], NULL);
   403     if (channel == NULL) {
   404 	return TCL_ERROR;
   405     }
   406     if (strcmp(argv[2], "readable") == 0) {
   407 	mask = TCL_READABLE;
   408     } else if (strcmp(argv[2], "writable") == 0){
   409 	mask = TCL_WRITABLE;
   410     } else if (strcmp(argv[2], "both") == 0){
   411 	mask = TCL_WRITABLE|TCL_READABLE;
   412     } else {
   413 	Tcl_AppendResult(interp, "bad argument \"", argv[2],
   414 		"\": must be readable, writable, or both", (char *) NULL);
   415 	return TCL_ERROR;
   416     }
   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);
   421 	return TCL_ERROR;
   422     }
   423     fd = (int) data;
   424     if (Tcl_GetInt(interp, argv[3], &timeout) != TCL_OK) {
   425 	return TCL_ERROR;
   426     }
   427     result = TclUnixWaitForFile(fd, mask, timeout);
   428     if (result & TCL_READABLE) {
   429 	Tcl_AppendElement(interp, "readable");
   430     }
   431     if (result & TCL_WRITABLE) {
   432 	Tcl_AppendElement(interp, "writable");
   433     }
   434     return TCL_OK;
   435 }
   436 
   437 /*
   438  *----------------------------------------------------------------------
   439  *
   440  * TestfindexecutableCmd --
   441  *
   442  *	This procedure implements the "testfindexecutable" command. It is
   443  *	used to test Tcl_FindExecutable.
   444  *
   445  * Results:
   446  *	A standard Tcl result.
   447  *
   448  * Side effects:
   449  *	None.
   450  *
   451  *----------------------------------------------------------------------
   452  */
   453 
   454 static int
   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. */
   460 {
   461     char *oldName;
   462     char *oldNativeName;
   463 
   464     if (argc != 2) {
   465 	Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0],
   466 		" argv0\"", (char *) NULL);
   467 	return TCL_ERROR;
   468     }
   469 
   470     oldName       = tclExecutableName;
   471     oldNativeName = tclNativeExecutableName;
   472 
   473     tclExecutableName       = NULL;
   474     tclNativeExecutableName = NULL;
   475 
   476     Tcl_FindExecutable(argv[1]);
   477     if (tclExecutableName != NULL) {
   478 	Tcl_SetResult(interp, tclExecutableName, TCL_VOLATILE);
   479 	ckfree(tclExecutableName);
   480     }
   481     if (tclNativeExecutableName != NULL) {
   482 	ckfree(tclNativeExecutableName);
   483     }
   484 
   485     tclExecutableName       = oldName;
   486     tclNativeExecutableName = oldNativeName;
   487 
   488     return TCL_OK;
   489 }
   490 
   491 /*
   492  *----------------------------------------------------------------------
   493  *
   494  * TestgetopenfileCmd --
   495  *
   496  *	This procedure implements the "testgetopenfile" command. It is
   497  *	used to get a FILE * value from a registered channel.
   498  *
   499  * Results:
   500  *	A standard Tcl result.
   501  *
   502  * Side effects:
   503  *	None.
   504  *
   505  *----------------------------------------------------------------------
   506  */
   507 
   508 static int
   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. */
   514 {
   515     ClientData filePtr;
   516 
   517     if (argc != 3) {
   518         Tcl_AppendResult(interp,
   519                 "wrong # args: should be \"", argv[0],
   520                 " channelName forWriting\"",
   521                 (char *) NULL);
   522         return TCL_ERROR;
   523     }
   524     if (Tcl_GetOpenFile(interp, argv[1], atoi(argv[2]), 1, &filePtr)
   525             == TCL_ERROR) {
   526         return TCL_ERROR;
   527     }
   528     if (filePtr == (ClientData) NULL) {
   529         Tcl_AppendResult(interp,
   530                 "Tcl_GetOpenFile succeeded but FILE * NULL!", (char *) NULL);
   531         return TCL_ERROR;
   532     }
   533     return TCL_OK;
   534 }
   535 
   536 /*
   537  *----------------------------------------------------------------------
   538  *
   539  * TestsetdefencdirCmd --
   540  *
   541  *	This procedure implements the "testsetdefenc" command. It is
   542  *	used to set the value of tclDefaultEncodingDir.
   543  *
   544  * Results:
   545  *	A standard Tcl result.
   546  *
   547  * Side effects:
   548  *	None.
   549  *
   550  *----------------------------------------------------------------------
   551  */
   552 
   553 static int
   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. */
   559 {
   560     if (argc != 2) {
   561         Tcl_AppendResult(interp,
   562                 "wrong # args: should be \"", argv[0],
   563                 " defaultDir\"",
   564                 (char *) NULL);
   565         return TCL_ERROR;
   566     }
   567 
   568     if (tclDefaultEncodingDir != NULL) {
   569 	ckfree(tclDefaultEncodingDir);
   570 	tclDefaultEncodingDir = NULL;
   571     }
   572     if (*argv[1] != '\0') {
   573 	tclDefaultEncodingDir = (char *)
   574 	    ckalloc((unsigned) strlen(argv[1]) + 1);
   575 	strcpy(tclDefaultEncodingDir, argv[1]);
   576     }
   577     return TCL_OK;
   578 }
   579 
   580 /*
   581  *----------------------------------------------------------------------
   582  *
   583  * TestgetdefencdirCmd --
   584  *
   585  *	This procedure implements the "testgetdefenc" command. It is
   586  *	used to get the value of tclDefaultEncodingDir.
   587  *
   588  * Results:
   589  *	A standard Tcl result.
   590  *
   591  * Side effects:
   592  *	None.
   593  *
   594  *----------------------------------------------------------------------
   595  */
   596 
   597 static int
   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. */
   603 {
   604     if (argc != 1) {
   605         Tcl_AppendResult(interp,
   606                 "wrong # args: should be \"", argv[0],
   607                 (char *) NULL);
   608         return TCL_ERROR;
   609     }
   610 
   611     if (tclDefaultEncodingDir != NULL) {
   612         Tcl_AppendResult(interp, tclDefaultEncodingDir, (char *) NULL);
   613     }
   614     return TCL_OK;
   615 }
   616 
   617 /*
   618  *----------------------------------------------------------------------
   619  * TestalarmCmd --
   620  *
   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.
   624  *
   625  * Results:
   626  *	None.
   627  *
   628  * Side Effects:
   629  *	Sets up an signal and async handlers.
   630  *
   631  *----------------------------------------------------------------------
   632  */
   633 
   634 static int
   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. */
   640 {
   641 #ifdef SA_RESTART
   642     unsigned int sec;
   643     struct sigaction action;
   644 
   645     if (argc > 1) {
   646 	Tcl_GetInt(interp, argv[1], (int *)&sec);
   647     } else {
   648 	sec = 1;
   649     }
   650 
   651     /*
   652      * Setup the signal handling that automatically retries
   653      * any interupted I/O system calls.
   654      */
   655     action.sa_handler = AlarmHandler;
   656     memset((void *)&action.sa_mask, 0, sizeof(sigset_t));
   657     action.sa_flags = SA_RESTART;
   658 
   659     if (sigaction(SIGALRM, &action, NULL) < 0) {
   660 	Tcl_AppendResult(interp, "sigaction: ", Tcl_PosixError(interp), NULL);
   661 	return TCL_ERROR;
   662     }
   663     (void)alarm(sec);
   664     return TCL_OK;
   665 #else
   666     Tcl_AppendResult(interp, "warning: sigaction SA_RESTART not support on this platform", NULL);
   667     return TCL_ERROR;
   668 #endif
   669 }
   670 
   671 /*
   672  *----------------------------------------------------------------------
   673  *
   674  * AlarmHandler --
   675  *
   676  *	Signal handler for the alarm command.
   677  *
   678  * Results:
   679  *	None.
   680  *
   681  * Side effects:
   682  * 	Calls the Tcl Async handler.
   683  *
   684  *----------------------------------------------------------------------
   685  */
   686 
   687 static void
   688 AlarmHandler()
   689 {
   690     gotsig = "1";
   691 }
   692 
   693 /*
   694  *----------------------------------------------------------------------
   695  * TestgotsigCmd --
   696  *
   697  * 	Verify the signal was handled after the testalarm command.
   698  *
   699  * Results:
   700  *	None.
   701  *
   702  * Side Effects:
   703  *	Resets the value of gotsig back to '0'.
   704  *
   705  *----------------------------------------------------------------------
   706  */
   707 
   708 static int
   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. */
   714 {
   715     Tcl_AppendResult(interp, gotsig, (char *) NULL);
   716     gotsig = "0";
   717     return TCL_OK;
   718 }
   719 
   720 /*
   721  *---------------------------------------------------------------------------
   722  *
   723  * TestchmodCmd --
   724  *
   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.
   729  *
   730  * Results:
   731  *	A standard Tcl result.
   732  *
   733  * Side effects:
   734  *	Changes permissions of specified files.
   735  *
   736  *---------------------------------------------------------------------------
   737  */
   738 
   739 static int
   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. */
   745 {
   746     int i, mode;
   747     char *rest;
   748 
   749     if (argc < 2) {
   750 	usage:
   751 	Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
   752 		" mode file ?file ...?", NULL);
   753 	return TCL_ERROR;
   754     }
   755 
   756     mode = (int) strtol(argv[1], &rest, 8);
   757     if ((rest == argv[1]) || (*rest != '\0')) {
   758 	goto usage;
   759     }
   760 
   761     for (i = 2; i < argc; i++) {
   762 	Tcl_DString buffer;
   763 	CONST char *translated;
   764 
   765 	translated = Tcl_TranslateFileName(interp, argv[i], &buffer);
   766 	if (translated == NULL) {
   767 	    return TCL_ERROR;
   768 	}
   769 	if (chmod(translated, (unsigned) mode) != 0) {
   770 	    Tcl_AppendResult(interp, translated, ": ", Tcl_PosixError(interp),
   771 		    NULL);
   772 	    return TCL_ERROR;
   773 	}
   774 	Tcl_DStringFree(&buffer);
   775     }
   776     return TCL_OK;
   777 }