tclUnixTest.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:22k
源码类别:

通讯编程

开发平台:

Visual C++

  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.  *
  9.  * See the file "license.terms" for information on usage and redistribution
  10.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  11.  *
  12.  * RCS: @(#) $Id: tclUnixTest.c,v 1.14.2.2 2006/03/19 22:47:30 vincentdarley Exp $
  13.  */
  14. #include "tclInt.h"
  15. #include "tclPort.h"
  16. /*
  17.  * The headers are needed for the testalarm command that verifies the
  18.  * use of SA_RESTART in signal handlers.
  19.  */
  20. #include <signal.h>
  21. #include <sys/resource.h>
  22. /*
  23.  * The following macros convert between TclFile's and fd's.  The conversion
  24.  * simple involves shifting fd's up by one to ensure that no valid fd is ever
  25.  * the same as NULL.  Note that this code is duplicated from tclUnixPipe.c
  26.  */
  27. #define MakeFile(fd) ((TclFile)((fd)+1))
  28. #define GetFd(file) (((int)file)-1)
  29. /*
  30.  * The stuff below is used to keep track of file handlers created and
  31.  * exercised by the "testfilehandler" command.
  32.  */
  33. typedef struct Pipe {
  34.     TclFile readFile; /* File handle for reading from the
  35.  * pipe.  NULL means pipe doesn't exist yet. */
  36.     TclFile writeFile; /* File handle for writing from the
  37.  * pipe. */
  38.     int readCount; /* Number of times the file handler for
  39.  * this file has triggered and the file
  40.  * was readable. */
  41.     int writeCount; /* Number of times the file handler for
  42.  * this file has triggered and the file
  43.  * was writable. */
  44. } Pipe;
  45. #define MAX_PIPES 10
  46. static Pipe testPipes[MAX_PIPES];
  47. /*
  48.  * The stuff below is used by the testalarm and testgotsig ommands.
  49.  */
  50. static char *gotsig = "0";
  51. /*
  52.  * Forward declarations of procedures defined later in this file:
  53.  */
  54. static void TestFileHandlerProc _ANSI_ARGS_((ClientData clientData,
  55.     int mask));
  56. static int TestfilehandlerCmd _ANSI_ARGS_((ClientData dummy,
  57.     Tcl_Interp *interp, int argc, CONST char **argv));
  58. static int TestfilewaitCmd _ANSI_ARGS_((ClientData dummy,
  59.     Tcl_Interp *interp, int argc, CONST char **argv));
  60. static int TestfindexecutableCmd _ANSI_ARGS_((ClientData dummy,
  61.     Tcl_Interp *interp, int argc, CONST char **argv));
  62. static int TestgetopenfileCmd _ANSI_ARGS_((ClientData dummy,
  63.     Tcl_Interp *interp, int argc, CONST char **argv));
  64. static int TestgetdefencdirCmd _ANSI_ARGS_((ClientData dummy,
  65.     Tcl_Interp *interp, int argc, CONST char **argv));
  66. static int TestsetdefencdirCmd _ANSI_ARGS_((ClientData dummy,
  67.     Tcl_Interp *interp, int argc, CONST char **argv));
  68. int TclplatformtestInit _ANSI_ARGS_((Tcl_Interp *interp));
  69. static int TestalarmCmd _ANSI_ARGS_((ClientData dummy,
  70.     Tcl_Interp *interp, int argc, CONST char **argv));
  71. static int TestgotsigCmd _ANSI_ARGS_((ClientData dummy,
  72.     Tcl_Interp *interp, int argc, CONST char **argv));
  73. static void  AlarmHandler _ANSI_ARGS_(());
  74. static int TestchmodCmd _ANSI_ARGS_((ClientData dummy,
  75.     Tcl_Interp *interp, int argc, CONST char **argv));
  76. /*
  77.  *----------------------------------------------------------------------
  78.  *
  79.  * TclplatformtestInit --
  80.  *
  81.  * Defines commands that test platform specific functionality for
  82.  * Unix platforms.
  83.  *
  84.  * Results:
  85.  * A standard Tcl result.
  86.  *
  87.  * Side effects:
  88.  * Defines new commands.
  89.  *
  90.  *----------------------------------------------------------------------
  91.  */
  92. int
  93. TclplatformtestInit(interp)
  94.     Tcl_Interp *interp; /* Interpreter to add commands to. */
  95. {
  96.     Tcl_CreateCommand(interp, "testchmod", TestchmodCmd,
  97.     (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
  98.     Tcl_CreateCommand(interp, "testfilehandler", TestfilehandlerCmd,
  99.             (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
  100.     Tcl_CreateCommand(interp, "testfilewait", TestfilewaitCmd,
  101.             (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
  102.     Tcl_CreateCommand(interp, "testfindexecutable", TestfindexecutableCmd,
  103.             (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
  104.     Tcl_CreateCommand(interp, "testgetopenfile", TestgetopenfileCmd,
  105.             (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
  106.     Tcl_CreateCommand(interp, "testgetdefenc", TestgetdefencdirCmd,
  107.             (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
  108.     Tcl_CreateCommand(interp, "testsetdefenc", TestsetdefencdirCmd,
  109.             (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
  110.     Tcl_CreateCommand(interp, "testalarm", TestalarmCmd,
  111.             (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
  112.     Tcl_CreateCommand(interp, "testgotsig", TestgotsigCmd,
  113.             (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
  114.     return TCL_OK;
  115. }
  116. /*
  117.  *----------------------------------------------------------------------
  118.  *
  119.  * TestfilehandlerCmd --
  120.  *
  121.  * This procedure implements the "testfilehandler" command. It is
  122.  * used to test Tcl_CreateFileHandler, Tcl_DeleteFileHandler, and
  123.  * TclWaitForFile.
  124.  *
  125.  * Results:
  126.  * A standard Tcl result.
  127.  *
  128.  * Side effects:
  129.  * None.
  130.  *
  131.  *----------------------------------------------------------------------
  132.  */
  133. static int
  134. TestfilehandlerCmd(clientData, interp, argc, argv)
  135.     ClientData clientData; /* Not used. */
  136.     Tcl_Interp *interp; /* Current interpreter. */
  137.     int argc; /* Number of arguments. */
  138.     CONST char **argv; /* Argument strings. */
  139. {
  140.     Pipe *pipePtr;
  141.     int i, mask, timeout;
  142.     static int initialized = 0;
  143.     char buffer[4000];
  144.     TclFile file;
  145.     /*
  146.      * NOTE: When we make this code work on Windows also, the following
  147.      * variable needs to be made Unix-only.
  148.      */
  149.     
  150.     if (!initialized) {
  151. for (i = 0; i < MAX_PIPES; i++) {
  152.     testPipes[i].readFile = NULL;
  153. }
  154. initialized = 1;
  155.     }
  156.     if (argc < 2) {
  157. Tcl_AppendResult(interp, "wrong # arguments: should be "", argv[0],
  158.                 " option ... "", (char *) NULL);
  159.         return TCL_ERROR;
  160.     }
  161.     pipePtr = NULL;
  162.     if (argc >= 3) {
  163. if (Tcl_GetInt(interp, argv[2], &i) != TCL_OK) {
  164.     return TCL_ERROR;
  165. }
  166. if (i >= MAX_PIPES) {
  167.     Tcl_AppendResult(interp, "bad index ", argv[2], (char *) NULL);
  168.     return TCL_ERROR;
  169. }
  170. pipePtr = &testPipes[i];
  171.     }
  172.     if (strcmp(argv[1], "close") == 0) {
  173. for (i = 0; i < MAX_PIPES; i++) {
  174.     if (testPipes[i].readFile != NULL) {
  175. TclpCloseFile(testPipes[i].readFile);
  176. testPipes[i].readFile = NULL;
  177. TclpCloseFile(testPipes[i].writeFile);
  178. testPipes[i].writeFile = NULL;
  179.     }
  180. }
  181.     } else if (strcmp(argv[1], "clear") == 0) {
  182. if (argc != 3) {
  183.     Tcl_AppendResult(interp, "wrong # arguments: should be "",
  184.                     argv[0], " clear index"", (char *) NULL);
  185.     return TCL_ERROR;
  186. }
  187. pipePtr->readCount = pipePtr->writeCount = 0;
  188.     } else if (strcmp(argv[1], "counts") == 0) {
  189. char buf[TCL_INTEGER_SPACE * 2];
  190. if (argc != 3) {
  191.     Tcl_AppendResult(interp, "wrong # arguments: should be "",
  192.                     argv[0], " counts index"", (char *) NULL);
  193.     return TCL_ERROR;
  194. }
  195. sprintf(buf, "%d %d", pipePtr->readCount, pipePtr->writeCount);
  196. Tcl_SetResult(interp, buf, TCL_VOLATILE);
  197.     } else if (strcmp(argv[1], "create") == 0) {
  198. if (argc != 5) {
  199.     Tcl_AppendResult(interp, "wrong # arguments: should be "",
  200.                     argv[0], " create index readMode writeMode"",
  201.                     (char *) NULL);
  202.     return TCL_ERROR;
  203. }
  204. if (pipePtr->readFile == NULL) {
  205.     if (!TclpCreatePipe(&pipePtr->readFile, &pipePtr->writeFile)) {
  206. Tcl_AppendResult(interp, "couldn't open pipe: ",
  207. Tcl_PosixError(interp), (char *) NULL);
  208. return TCL_ERROR;
  209.     }
  210. #ifdef O_NONBLOCK
  211.     fcntl(GetFd(pipePtr->readFile), F_SETFL, O_NONBLOCK);
  212.     fcntl(GetFd(pipePtr->writeFile), F_SETFL, O_NONBLOCK);
  213. #else
  214.     Tcl_SetResult(interp, "can't make pipes non-blocking",
  215.     TCL_STATIC);
  216.     return TCL_ERROR;
  217. #endif
  218. }
  219. pipePtr->readCount = 0;
  220. pipePtr->writeCount = 0;
  221. if (strcmp(argv[3], "readable") == 0) {
  222.     Tcl_CreateFileHandler(GetFd(pipePtr->readFile), TCL_READABLE,
  223.     TestFileHandlerProc, (ClientData) pipePtr);
  224. } else if (strcmp(argv[3], "off") == 0) {
  225.     Tcl_DeleteFileHandler(GetFd(pipePtr->readFile));
  226. } else if (strcmp(argv[3], "disabled") == 0) {
  227.     Tcl_CreateFileHandler(GetFd(pipePtr->readFile), 0,
  228.     TestFileHandlerProc, (ClientData) pipePtr);
  229. } else {
  230.     Tcl_AppendResult(interp, "bad read mode "", argv[3], """,
  231.     (char *) NULL);
  232.     return TCL_ERROR;
  233. }
  234. if (strcmp(argv[4], "writable") == 0) {
  235.     Tcl_CreateFileHandler(GetFd(pipePtr->writeFile), TCL_WRITABLE,
  236.     TestFileHandlerProc, (ClientData) pipePtr);
  237. } else if (strcmp(argv[4], "off") == 0) {
  238.     Tcl_DeleteFileHandler(GetFd(pipePtr->writeFile));
  239. } else if (strcmp(argv[4], "disabled") == 0) {
  240.     Tcl_CreateFileHandler(GetFd(pipePtr->writeFile), 0,
  241.     TestFileHandlerProc, (ClientData) pipePtr);
  242. } else {
  243.     Tcl_AppendResult(interp, "bad read mode "", argv[4], """,
  244.     (char *) NULL);
  245.     return TCL_ERROR;
  246. }
  247.     } else if (strcmp(argv[1], "empty") == 0) {
  248. if (argc != 3) {
  249.     Tcl_AppendResult(interp, "wrong # arguments: should be "",
  250.                     argv[0], " empty index"", (char *) NULL);
  251.     return TCL_ERROR;
  252. }
  253.         while (read(GetFd(pipePtr->readFile), buffer, 4000) > 0) {
  254.             /* Empty loop body. */
  255.         }
  256.     } else if (strcmp(argv[1], "fill") == 0) {
  257. if (argc != 3) {
  258.     Tcl_AppendResult(interp, "wrong # arguments: should be "",
  259.                     argv[0], " fill index"", (char *) NULL);
  260.     return TCL_ERROR;
  261. }
  262. memset((VOID *) buffer, 'a', 4000);
  263.         while (write(GetFd(pipePtr->writeFile), buffer, 4000) > 0) {
  264.             /* Empty loop body. */
  265.         }
  266.     } else if (strcmp(argv[1], "fillpartial") == 0) {
  267. char buf[TCL_INTEGER_SPACE];
  268. if (argc != 3) {
  269.     Tcl_AppendResult(interp, "wrong # arguments: should be "",
  270.                     argv[0], " fillpartial index"", (char *) NULL);
  271.     return TCL_ERROR;
  272. }
  273. memset((VOID *) buffer, 'b', 10);
  274. TclFormatInt(buf, write(GetFd(pipePtr->writeFile), buffer, 10));
  275. Tcl_SetResult(interp, buf, TCL_VOLATILE);
  276.     } else if (strcmp(argv[1], "oneevent") == 0) {
  277. Tcl_DoOneEvent(TCL_FILE_EVENTS|TCL_DONT_WAIT);
  278.     } else if (strcmp(argv[1], "wait") == 0) {
  279. if (argc != 5) {
  280.     Tcl_AppendResult(interp, "wrong # arguments: should be "",
  281.                     argv[0], " wait index readable|writable timeout"",
  282.                     (char *) NULL);
  283.     return TCL_ERROR;
  284. }
  285. if (pipePtr->readFile == NULL) {
  286.     Tcl_AppendResult(interp, "pipe ", argv[2], " doesn't exist",
  287.     (char *) NULL);
  288.     return TCL_ERROR;
  289. }
  290. if (strcmp(argv[3], "readable") == 0) {
  291.     mask = TCL_READABLE;
  292.     file = pipePtr->readFile;
  293. } else {
  294.     mask = TCL_WRITABLE;
  295.     file = pipePtr->writeFile;
  296. }
  297. if (Tcl_GetInt(interp, argv[4], &timeout) != TCL_OK) {
  298.     return TCL_ERROR;
  299. }
  300. i = TclUnixWaitForFile(GetFd(file), mask, timeout);
  301. if (i & TCL_READABLE) {
  302.     Tcl_AppendElement(interp, "readable");
  303. }
  304. if (i & TCL_WRITABLE) {
  305.     Tcl_AppendElement(interp, "writable");
  306. }
  307.     } else if (strcmp(argv[1], "windowevent") == 0) {
  308. Tcl_DoOneEvent(TCL_WINDOW_EVENTS|TCL_DONT_WAIT);
  309.     } else {
  310. Tcl_AppendResult(interp, "bad option "", argv[1],
  311. "": must be close, clear, counts, create, empty, fill, ",
  312. "fillpartial, oneevent, wait, or windowevent",
  313. (char *) NULL);
  314. return TCL_ERROR;
  315.     }
  316.     return TCL_OK;
  317. }
  318. static void TestFileHandlerProc(clientData, mask)
  319.     ClientData clientData; /* Points to a Pipe structure. */
  320.     int mask; /* Indicates which events happened:
  321.  * TCL_READABLE or TCL_WRITABLE. */
  322. {
  323.     Pipe *pipePtr = (Pipe *) clientData;
  324.     if (mask & TCL_READABLE) {
  325. pipePtr->readCount++;
  326.     }
  327.     if (mask & TCL_WRITABLE) {
  328. pipePtr->writeCount++;
  329.     }
  330. }
  331. /*
  332.  *----------------------------------------------------------------------
  333.  *
  334.  * TestfilewaitCmd --
  335.  *
  336.  * This procedure implements the "testfilewait" command. It is
  337.  * used to test TclUnixWaitForFile.
  338.  *
  339.  * Results:
  340.  * A standard Tcl result.
  341.  *
  342.  * Side effects:
  343.  * None.
  344.  *
  345.  *----------------------------------------------------------------------
  346.  */
  347. static int
  348. TestfilewaitCmd(clientData, interp, argc, argv)
  349.     ClientData clientData; /* Not used. */
  350.     Tcl_Interp *interp; /* Current interpreter. */
  351.     int argc; /* Number of arguments. */
  352.     CONST char **argv; /* Argument strings. */
  353. {
  354.     int mask, result, timeout;
  355.     Tcl_Channel channel;
  356.     int fd;
  357.     ClientData data;
  358.     if (argc != 4) {
  359. Tcl_AppendResult(interp, "wrong # arguments: should be "", argv[0],
  360. " file readable|writable|both timeout"", (char *) NULL);
  361. return TCL_ERROR;
  362.     }
  363.     channel = Tcl_GetChannel(interp, argv[1], NULL);
  364.     if (channel == NULL) {
  365. return TCL_ERROR;
  366.     }
  367.     if (strcmp(argv[2], "readable") == 0) {
  368. mask = TCL_READABLE;
  369.     } else if (strcmp(argv[2], "writable") == 0){
  370. mask = TCL_WRITABLE;
  371.     } else if (strcmp(argv[2], "both") == 0){
  372. mask = TCL_WRITABLE|TCL_READABLE;
  373.     } else {
  374. Tcl_AppendResult(interp, "bad argument "", argv[2],
  375. "": must be readable, writable, or both", (char *) NULL);
  376. return TCL_ERROR;
  377.     }
  378.     if (Tcl_GetChannelHandle(channel, 
  379.     (mask & TCL_READABLE) ? TCL_READABLE : TCL_WRITABLE,
  380.     (ClientData*) &data) != TCL_OK) {
  381. Tcl_SetResult(interp, "couldn't get channel file", TCL_STATIC);
  382. return TCL_ERROR;
  383.     }
  384.     fd = (int) data;
  385.     if (Tcl_GetInt(interp, argv[3], &timeout) != TCL_OK) {
  386. return TCL_ERROR;
  387.     }
  388.     result = TclUnixWaitForFile(fd, mask, timeout);
  389.     if (result & TCL_READABLE) {
  390. Tcl_AppendElement(interp, "readable");
  391.     }
  392.     if (result & TCL_WRITABLE) {
  393. Tcl_AppendElement(interp, "writable");
  394.     }
  395.     return TCL_OK;
  396. }
  397. /*
  398.  *----------------------------------------------------------------------
  399.  *
  400.  * TestfindexecutableCmd --
  401.  *
  402.  * This procedure implements the "testfindexecutable" command. It is
  403.  * used to test Tcl_FindExecutable.
  404.  *
  405.  * Results:
  406.  * A standard Tcl result.
  407.  *
  408.  * Side effects:
  409.  * None.
  410.  *
  411.  *----------------------------------------------------------------------
  412.  */
  413. static int
  414. TestfindexecutableCmd(clientData, interp, argc, argv)
  415.     ClientData clientData; /* Not used. */
  416.     Tcl_Interp *interp; /* Current interpreter. */
  417.     int argc; /* Number of arguments. */
  418.     CONST char **argv; /* Argument strings. */
  419. {
  420.     char *oldName;
  421.     char *oldNativeName;
  422.     if (argc != 2) {
  423. Tcl_AppendResult(interp, "wrong # arguments: should be "", argv[0],
  424. " argv0"", (char *) NULL);
  425. return TCL_ERROR;
  426.     }
  427.     oldName       = tclExecutableName;
  428.     oldNativeName = tclNativeExecutableName;
  429.     tclExecutableName       = NULL;
  430.     tclNativeExecutableName = NULL;
  431.     Tcl_FindExecutable(argv[1]);
  432.     if (tclExecutableName != NULL) {
  433. Tcl_SetResult(interp, tclExecutableName, TCL_VOLATILE);
  434. ckfree(tclExecutableName);
  435.     }
  436.     if (tclNativeExecutableName != NULL) {
  437. ckfree(tclNativeExecutableName);
  438.     }
  439.     tclExecutableName       = oldName;
  440.     tclNativeExecutableName = oldNativeName;
  441.     return TCL_OK;
  442. }
  443. /*
  444.  *----------------------------------------------------------------------
  445.  *
  446.  * TestgetopenfileCmd --
  447.  *
  448.  * This procedure implements the "testgetopenfile" command. It is
  449.  * used to get a FILE * value from a registered channel.
  450.  *
  451.  * Results:
  452.  * A standard Tcl result.
  453.  *
  454.  * Side effects:
  455.  * None.
  456.  *
  457.  *----------------------------------------------------------------------
  458.  */
  459. static int
  460. TestgetopenfileCmd(clientData, interp, argc, argv)
  461.     ClientData clientData; /* Not used. */
  462.     Tcl_Interp *interp; /* Current interpreter. */
  463.     int argc; /* Number of arguments. */
  464.     CONST char **argv; /* Argument strings. */
  465. {
  466.     ClientData filePtr;
  467.     if (argc != 3) {
  468.         Tcl_AppendResult(interp,
  469.                 "wrong # args: should be "", argv[0],
  470.                 " channelName forWriting"",
  471.                 (char *) NULL);
  472.         return TCL_ERROR;
  473.     }
  474.     if (Tcl_GetOpenFile(interp, argv[1], atoi(argv[2]), 1, &filePtr)
  475.             == TCL_ERROR) {
  476.         return TCL_ERROR;
  477.     }
  478.     if (filePtr == (ClientData) NULL) {
  479.         Tcl_AppendResult(interp,
  480.                 "Tcl_GetOpenFile succeeded but FILE * NULL!", (char *) NULL);
  481.         return TCL_ERROR;
  482.     }
  483.     return TCL_OK;
  484. }
  485. /*
  486.  *----------------------------------------------------------------------
  487.  *
  488.  * TestsetdefencdirCmd --
  489.  *
  490.  * This procedure implements the "testsetdefenc" command. It is
  491.  * used to set the value of tclDefaultEncodingDir.
  492.  *
  493.  * Results:
  494.  * A standard Tcl result.
  495.  *
  496.  * Side effects:
  497.  * None.
  498.  *
  499.  *----------------------------------------------------------------------
  500.  */
  501. static int
  502. TestsetdefencdirCmd(clientData, interp, argc, argv)
  503.     ClientData clientData; /* Not used. */
  504.     Tcl_Interp *interp; /* Current interpreter. */
  505.     int argc; /* Number of arguments. */
  506.     CONST char **argv; /* Argument strings. */
  507. {
  508.     if (argc != 2) {
  509.         Tcl_AppendResult(interp,
  510.                 "wrong # args: should be "", argv[0],
  511.                 " defaultDir"",
  512.                 (char *) NULL);
  513.         return TCL_ERROR;
  514.     }
  515.     if (tclDefaultEncodingDir != NULL) {
  516. ckfree(tclDefaultEncodingDir);
  517. tclDefaultEncodingDir = NULL;
  518.     }
  519.     if (*argv[1] != '') {
  520. tclDefaultEncodingDir = (char *)
  521.     ckalloc((unsigned) strlen(argv[1]) + 1);
  522. strcpy(tclDefaultEncodingDir, argv[1]);
  523.     }
  524.     return TCL_OK;
  525. }
  526. /*
  527.  *----------------------------------------------------------------------
  528.  *
  529.  * TestgetdefencdirCmd --
  530.  *
  531.  * This procedure implements the "testgetdefenc" command. It is
  532.  * used to get the value of tclDefaultEncodingDir.
  533.  *
  534.  * Results:
  535.  * A standard Tcl result.
  536.  *
  537.  * Side effects:
  538.  * None.
  539.  *
  540.  *----------------------------------------------------------------------
  541.  */
  542. static int
  543. TestgetdefencdirCmd(clientData, interp, argc, argv)
  544.     ClientData clientData; /* Not used. */
  545.     Tcl_Interp *interp; /* Current interpreter. */
  546.     int argc; /* Number of arguments. */
  547.     CONST char **argv; /* Argument strings. */
  548. {
  549.     if (argc != 1) {
  550.         Tcl_AppendResult(interp,
  551.                 "wrong # args: should be "", argv[0],
  552.                 (char *) NULL);
  553.         return TCL_ERROR;
  554.     }
  555.     if (tclDefaultEncodingDir != NULL) {
  556.         Tcl_AppendResult(interp, tclDefaultEncodingDir, (char *) NULL);
  557.     }
  558.     return TCL_OK;
  559. }
  560. /*
  561.  *----------------------------------------------------------------------
  562.  * TestalarmCmd --
  563.  *
  564.  * Test that EINTR is handled correctly by generating and
  565.  * handling a signal.  This requires using the SA_RESTART
  566.  * flag when registering the signal handler.
  567.  *
  568.  * Results:
  569.  * None.
  570.  *
  571.  * Side Effects:
  572.  * Sets up an signal and async handlers.
  573.  *
  574.  *----------------------------------------------------------------------
  575.  */
  576. static int
  577. TestalarmCmd(clientData, interp, argc, argv)
  578.     ClientData clientData; /* Not used. */
  579.     Tcl_Interp *interp; /* Current interpreter. */
  580.     int argc; /* Number of arguments. */
  581.     CONST char **argv; /* Argument strings. */
  582. {
  583. #ifdef SA_RESTART
  584.     unsigned int sec;
  585.     struct sigaction action;
  586.     if (argc > 1) {
  587. Tcl_GetInt(interp, argv[1], (int *)&sec);
  588.     } else {
  589. sec = 1;
  590.     }
  591.     /*
  592.      * Setup the signal handling that automatically retries
  593.      * any interupted I/O system calls.
  594.      */
  595.     action.sa_handler = AlarmHandler;
  596.     memset((void *)&action.sa_mask, 0, sizeof(sigset_t));
  597.     action.sa_flags = SA_RESTART;
  598.     if (sigaction(SIGALRM, &action, NULL) < 0) {
  599. Tcl_AppendResult(interp, "sigaction: ", Tcl_PosixError(interp), NULL);
  600. return TCL_ERROR;
  601.     }
  602.     (void)alarm(sec);
  603.     return TCL_OK;
  604. #else
  605.     Tcl_AppendResult(interp, "warning: sigaction SA_RESTART not support on this platform", NULL);
  606.     return TCL_ERROR;
  607. #endif
  608. }
  609. /*
  610.  *----------------------------------------------------------------------
  611.  *
  612.  * AlarmHandler --
  613.  *
  614.  * Signal handler for the alarm command.
  615.  *
  616.  * Results:
  617.  * None.
  618.  *
  619.  * Side effects:
  620.  *  Calls the Tcl Async handler.
  621.  *
  622.  *----------------------------------------------------------------------
  623.  */
  624. static void
  625. AlarmHandler()
  626. {
  627.     gotsig = "1";
  628. }
  629. /*
  630.  *----------------------------------------------------------------------
  631.  * TestgotsigCmd --
  632.  *
  633.  *  Verify the signal was handled after the testalarm command.
  634.  *
  635.  * Results:
  636.  * None.
  637.  *
  638.  * Side Effects:
  639.  * Resets the value of gotsig back to '0'.
  640.  *
  641.  *----------------------------------------------------------------------
  642.  */
  643. static int
  644. TestgotsigCmd(clientData, interp, argc, argv)
  645.     ClientData clientData; /* Not used. */
  646.     Tcl_Interp *interp; /* Current interpreter. */
  647.     int argc; /* Number of arguments. */
  648.     CONST char **argv; /* Argument strings. */
  649. {
  650.     Tcl_AppendResult(interp, gotsig, (char *) NULL);
  651.     gotsig = "0";
  652.     return TCL_OK;
  653. }
  654. /*
  655.  *---------------------------------------------------------------------------
  656.  *
  657.  * TestchmodCmd --
  658.  *
  659.  * Implements the "testchmod" cmd.  Used when testing "file" command.
  660.  * The only attribute used by the Windows platform is the user write
  661.  * flag; if this is not set, the file is made read-only.  Otehrwise, the
  662.  * file is made read-write.
  663.  *
  664.  * Results:
  665.  * A standard Tcl result.
  666.  *
  667.  * Side effects:
  668.  * Changes permissions of specified files.
  669.  *
  670.  *---------------------------------------------------------------------------
  671.  */
  672. static int
  673. TestchmodCmd(dummy, interp, argc, argv)
  674.     ClientData dummy; /* Not used. */
  675.     Tcl_Interp *interp; /* Current interpreter. */
  676.     int argc; /* Number of arguments. */
  677.     CONST char **argv; /* Argument strings. */
  678. {
  679.     int i, mode;
  680.     char *rest;
  681.     if (argc < 2) {
  682. usage:
  683. Tcl_AppendResult(interp, "wrong # args: should be "", argv[0],
  684. " mode file ?file ...?", NULL);
  685. return TCL_ERROR;
  686.     }
  687.     mode = (int) strtol(argv[1], &rest, 8);
  688.     if ((rest == argv[1]) || (*rest != '')) {
  689. goto usage;
  690.     }
  691.     for (i = 2; i < argc; i++) {
  692. Tcl_DString buffer;
  693. CONST char *translated;
  694. translated = Tcl_TranslateFileName(interp, argv[i], &buffer);
  695. if (translated == NULL) {
  696.     return TCL_ERROR;
  697. }
  698. if (chmod(translated, (unsigned) mode) != 0) {
  699.     Tcl_AppendResult(interp, translated, ": ", Tcl_PosixError(interp),
  700.     NULL);
  701.     return TCL_ERROR;
  702. }
  703. Tcl_DStringFree(&buffer);
  704.     }
  705.     return TCL_OK;
  706. }