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