summaryrefslogtreecommitdiffstats
path: root/win/tclWinPipe.c
diff options
context:
space:
mode:
Diffstat (limited to 'win/tclWinPipe.c')
-rw-r--r--win/tclWinPipe.c343
1 files changed, 192 insertions, 151 deletions
diff --git a/win/tclWinPipe.c b/win/tclWinPipe.c
index cf1cdb1..b9b881c 100644
--- a/win/tclWinPipe.c
+++ b/win/tclWinPipe.c
@@ -194,7 +194,7 @@ static DWORD WINAPI PipeReaderThread(LPVOID arg);
static void PipeSetupProc(ClientData clientData, int flags);
static void PipeWatchProc(ClientData instanceData, int mask);
static DWORD WINAPI PipeWriterThread(LPVOID arg);
-static int TempFileName(WCHAR name[MAX_PATH]);
+static int TempFileName(TCHAR name[MAX_PATH]);
static int WaitForRead(PipeInfo *infoPtr, int blocking);
static void PipeThreadActionProc(ClientData instanceData,
int action);
@@ -204,7 +204,7 @@ static void PipeThreadActionProc(ClientData instanceData,
* I/O.
*/
-static Tcl_ChannelType pipeChannelType = {
+static const Tcl_ChannelType pipeChannelType = {
"pipe", /* Type name. */
TCL_CHANNEL_VERSION_5, /* v5 channel */
TCL_CLOSE2PROC, /* Close proc. */
@@ -221,7 +221,7 @@ static Tcl_ChannelType pipeChannelType = {
NULL, /* handler proc. */
NULL, /* wide seek proc */
PipeThreadActionProc, /* thread action proc */
- NULL, /* truncate */
+ NULL /* truncate */
};
/*
@@ -412,7 +412,7 @@ PipeCheckProc(
if (needEvent) {
infoPtr->flags |= PIPE_PENDING;
- evPtr = (PipeEvent *) ckalloc(sizeof(PipeEvent));
+ evPtr = ckalloc(sizeof(PipeEvent));
evPtr->header.proc = PipeEventProc;
evPtr->infoPtr = infoPtr;
Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL);
@@ -443,7 +443,7 @@ TclWinMakeFile(
{
WinFile *filePtr;
- filePtr = (WinFile *) ckalloc(sizeof(WinFile));
+ filePtr = ckalloc(sizeof(WinFile));
filePtr->type = WIN_FILE;
filePtr->handle = handle;
@@ -472,27 +472,18 @@ TclWinMakeFile(
static int
TempFileName(
- WCHAR name[MAX_PATH]) /* Buffer in which name for temporary file
+ TCHAR name[MAX_PATH]) /* Buffer in which name for temporary file
* gets stored. */
{
- TCHAR *prefix;
-
- prefix = (tclWinProcs->useWide) ? (TCHAR *) L"TCL" : (TCHAR *) "TCL";
- if ((*tclWinProcs->getTempPathProc)(MAX_PATH, name) != 0) {
- if ((*tclWinProcs->getTempFileNameProc)((TCHAR *) name, prefix, 0,
- name) != 0) {
+ TCHAR *prefix = TEXT("TCL");
+ if (GetTempPath(MAX_PATH, name) != 0) {
+ if (GetTempFileName(name, prefix, 0, name) != 0) {
return 1;
}
}
- if (tclWinProcs->useWide) {
- ((WCHAR *) name)[0] = '.';
- ((WCHAR *) name)[1] = '\0';
- } else {
- ((char *) name)[0] = '.';
- ((char *) name)[1] = '\0';
- }
- return (*tclWinProcs->getTempFileNameProc)((TCHAR *) name, prefix, 0,
- name);
+ name[0] = '.';
+ name[1] = '\0';
+ return GetTempFileName(name, prefix, 0, name);
}
/*
@@ -604,7 +595,7 @@ TclpOpenFile(
flags = 0;
if (!(mode & O_CREAT)) {
- flags = (*tclWinProcs->getFileAttributesProc)(nativePath);
+ flags = GetFileAttributes(nativePath);
if (flags == 0xFFFFFFFF) {
flags = 0;
}
@@ -620,8 +611,8 @@ TclpOpenFile(
* Now we get to create the file.
*/
- handle = (*tclWinProcs->createFileProc)(nativePath, accessMode,
- shareMode, NULL, createMode, flags, NULL);
+ handle = CreateFile(nativePath, accessMode, shareMode,
+ NULL, createMode, flags, NULL);
Tcl_DStringFree(&ds);
if (handle == INVALID_HANDLE_VALUE) {
@@ -668,7 +659,7 @@ TclFile
TclpCreateTempFile(
const char *contents) /* String to write into temp file, or NULL. */
{
- WCHAR name[MAX_PATH];
+ TCHAR name[MAX_PATH];
const char *native;
Tcl_DString dstring;
HANDLE handle;
@@ -677,7 +668,7 @@ TclpCreateTempFile(
return NULL;
}
- handle = (*tclWinProcs->createFileProc)((TCHAR *) name,
+ handle = CreateFile(name,
GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_TEMPORARY|FILE_FLAG_DELETE_ON_CLOSE, NULL);
if (handle == INVALID_HANDLE_VALUE) {
@@ -737,7 +728,7 @@ TclpCreateTempFile(
TclWinConvertError(GetLastError());
CloseHandle(handle);
- (*tclWinProcs->deleteFileProc)((TCHAR *) name);
+ DeleteFile(name);
return NULL;
}
@@ -760,13 +751,13 @@ TclpCreateTempFile(
Tcl_Obj *
TclpTempFileName(void)
{
- WCHAR fileName[MAX_PATH];
+ TCHAR fileName[MAX_PATH];
if (TempFileName(fileName) == 0) {
return NULL;
}
- return TclpNativeToNormalized((ClientData) fileName);
+ return TclpNativeToNormalized(fileName);
}
/*
@@ -842,7 +833,7 @@ TclpCloseFile(
if (filePtr->handle != NULL &&
CloseHandle(filePtr->handle) == FALSE) {
TclWinConvertError(GetLastError());
- ckfree((char *) filePtr);
+ ckfree(filePtr);
return -1;
}
}
@@ -852,7 +843,7 @@ TclpCloseFile(
Tcl_Panic("TclpCloseFile: unexpected file type");
}
- ckfree((char *) filePtr);
+ ckfree(filePtr);
return 0;
}
@@ -953,7 +944,7 @@ TclpCreateProcess(
{
int result, applType, createFlags;
Tcl_DString cmdLine; /* Complete command line (TCHAR). */
- STARTUPINFOA startInfo;
+ STARTUPINFO startInfo;
PROCESS_INFORMATION procInfo;
SECURITY_ATTRIBUTES secAtts;
HANDLE hProcess, h, inputHandle, outputHandle, errorHandle;
@@ -1142,82 +1133,12 @@ TclpCreateProcess(
}
if (applType == APPL_DOS) {
- /*
- * Under Windows 95, 16-bit DOS applications do not work well with
- * pipes:
- *
- * 1. EOF on a pipe between a detached 16-bit DOS application and
- * another application is not seen at the other end of the pipe,
- * so the listening process blocks forever on reads. This inablity
- * to detect EOF happens when either a 16-bit app or the 32-bit
- * app is the listener.
- *
- * 2. If a 16-bit DOS application (detached or not) blocks when
- * writing to a pipe, it will never wake up again, and it
- * eventually brings the whole system down around it.
- *
- * The 16-bit application is run as a normal process inside of a
- * hidden helper console app, and this helper may be run as a
- * detached process. If any of the stdio handles is a pipe, the
- * helper application accumulates information into temp files and
- * forwards it to or from the DOS application as appropriate.
- * This means that DOS apps must receive EOF from a stdin pipe
- * before they will actually begin, and must finish generating
- * stdout or stderr before the data will be sent to the next stage
- * of the pipe.
- *
- * The helper app should be located in the same directory as the
- * tcl dll.
- */
- Tcl_Obj *tclExePtr, *pipeDllPtr;
- char *start, *end;
- int i, fileExists;
- Tcl_DString pipeDll;
-
- if (createFlags != 0) {
- startInfo.wShowWindow = SW_HIDE;
- startInfo.dwFlags |= STARTF_USESHOWWINDOW;
- createFlags = CREATE_NEW_CONSOLE;
- }
-
- Tcl_DStringInit(&pipeDll);
- Tcl_DStringAppend(&pipeDll, TCL_PIPE_DLL, -1);
- tclExePtr = TclGetObjNameOfExecutable();
- Tcl_IncrRefCount(tclExePtr);
- start = Tcl_GetStringFromObj(tclExePtr, &i);
- for (end = start + (i-1); end > start; end--) {
- if (*end == '/') {
- break;
- }
- }
- if (*end != '/') {
- Tcl_AppendResult(interp, "no / in executable path name \"",
- start, "\"", (char *) NULL);
- Tcl_DecrRefCount(tclExePtr);
- Tcl_DStringFree(&pipeDll);
- goto end;
- }
- i = (end - start) + 1;
- pipeDllPtr = Tcl_NewStringObj(start, i);
- Tcl_AppendToObj(pipeDllPtr, Tcl_DStringValue(&pipeDll), -1);
- Tcl_IncrRefCount(pipeDllPtr);
- if (Tcl_FSConvertToPathType(interp, pipeDllPtr) != TCL_OK) {
- Tcl_Panic("Tcl_FSConvertToPathType failed");
- }
- fileExists = (Tcl_FSAccess(pipeDllPtr, F_OK) == 0);
- if (!fileExists) {
- Tcl_AppendResult(interp, "Tcl pipe dll \"",
- Tcl_DStringValue(&pipeDll), "\" not found",
- (char *) NULL);
- Tcl_DecrRefCount(tclExePtr);
- Tcl_DecrRefCount(pipeDllPtr);
- Tcl_DStringFree(&pipeDll);
- goto end;
- }
- Tcl_DStringAppend(&cmdLine, Tcl_DStringValue(&pipeDll), -1);
- Tcl_DecrRefCount(tclExePtr);
- Tcl_DecrRefCount(pipeDllPtr);
- Tcl_DStringFree(&pipeDll);
+ Tcl_AppendResult(interp,
+ "DOS application process not supported on this platform",
+ (char *) NULL);
+ Tcl_SetErrorCode(interp, "TCL", "OPERATION", "EXEC", "DOS_APP",
+ NULL);
+ goto end;
}
}
@@ -1241,7 +1162,7 @@ TclpCreateProcess(
BuildCommandLine(execPath, argc, argv, &cmdLine);
- if ((*tclWinProcs->createProcessProc)(NULL,
+ if (CreateProcess(NULL,
(TCHAR *) Tcl_DStringValue(&cmdLine), NULL, NULL, TRUE,
(DWORD) createFlags, NULL, NULL, &startInfo, &procInfo) == 0) {
TclWinConvertError(GetLastError());
@@ -1374,7 +1295,7 @@ ApplicationType(
IMAGE_DOS_HEADER header;
Tcl_DString nameBuf, ds;
const TCHAR *nativeName;
- WCHAR nativeFullPath[MAX_PATH];
+ TCHAR nativeFullPath[MAX_PATH];
static char extensions[][5] = {"", ".com", ".exe", ".bat"};
/*
@@ -1400,8 +1321,8 @@ ApplicationType(
Tcl_DStringAppend(&nameBuf, extensions[i], -1);
nativeName = Tcl_WinUtfToTChar(Tcl_DStringValue(&nameBuf),
Tcl_DStringLength(&nameBuf), &ds);
- found = (*tclWinProcs->searchPathProc)(NULL, nativeName, NULL,
- MAX_PATH, nativeFullPath, &rest);
+ found = SearchPath(NULL, nativeName, NULL, MAX_PATH,
+ nativeFullPath, &rest);
Tcl_DStringFree(&ds);
if (found == 0) {
continue;
@@ -1412,11 +1333,11 @@ ApplicationType(
* known type.
*/
- attr = (*tclWinProcs->getFileAttributesProc)((TCHAR *) nativeFullPath);
+ attr = GetFileAttributes(nativeFullPath);
if ((attr == 0xffffffff) || (attr & FILE_ATTRIBUTE_DIRECTORY)) {
continue;
}
- strcpy(fullName, Tcl_WinTCharToUtf((TCHAR *) nativeFullPath, -1, &ds));
+ strcpy(fullName, Tcl_WinTCharToUtf(nativeFullPath, -1, &ds));
Tcl_DStringFree(&ds);
ext = strrchr(fullName, '.');
@@ -1425,7 +1346,7 @@ ApplicationType(
break;
}
- hFile = (*tclWinProcs->createFileProc)((TCHAR *) nativeFullPath,
+ hFile = CreateFile(nativeFullPath,
GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
@@ -1505,9 +1426,8 @@ ApplicationType(
* application name from the arguments.
*/
- (*tclWinProcs->getShortPathNameProc)((TCHAR *) nativeFullPath,
- nativeFullPath, MAX_PATH);
- strcpy(fullName, Tcl_WinTCharToUtf((TCHAR *) nativeFullPath, -1, &ds));
+ GetShortPathName(nativeFullPath, nativeFullPath, MAX_PATH);
+ strcpy(fullName, Tcl_WinTCharToUtf(nativeFullPath, -1, &ds));
Tcl_DStringFree(&ds);
}
return applType;
@@ -1570,6 +1490,7 @@ BuildCommandLine(
} else {
int count;
Tcl_UniChar ch;
+
for (start = arg; *start != '\0'; start += count) {
count = Tcl_UtfToUniChar(start, &ch);
if (Tcl_UniCharIsSpace(ch)) { /* INTL: ISO space. */
@@ -1653,9 +1574,8 @@ TclpCreateCommandChannel(
Tcl_Pid *pidPtr) /* An array of process identifiers. */
{
char channelName[16 + TCL_INTEGER_SPACE];
- int channelId;
DWORD id;
- PipeInfo *infoPtr = (PipeInfo *) ckalloc((unsigned) sizeof(PipeInfo));
+ PipeInfo *infoPtr = ckalloc(sizeof(PipeInfo));
PipeInit();
@@ -1670,21 +1590,7 @@ TclpCreateCommandChannel(
infoPtr->writeBuf = 0;
infoPtr->writeBufLen = 0;
infoPtr->writeError = 0;
- infoPtr->channel = (Tcl_Channel) NULL;
-
- /*
- * Use one of the fds associated with the channel as the channel id.
- */
-
- if (readFile) {
- channelId = (int) ((WinFile*)readFile)->handle;
- } else if (writeFile) {
- channelId = (int) ((WinFile*)writeFile)->handle;
- } else if (errorFile) {
- channelId = (int) ((WinFile*)errorFile)->handle;
- } else {
- channelId = 0;
- }
+ infoPtr->channel = NULL;
infoPtr->validMask = 0;
@@ -1726,9 +1632,9 @@ TclpCreateCommandChannel(
* unique, in case channels share handles (stdin/stdout).
*/
- wsprintfA(channelName, "file%lx", infoPtr);
+ sprintf(channelName, "file%" TCL_I_MODIFIER "x", (size_t) infoPtr);
infoPtr->channel = Tcl_CreateChannel(&pipeChannelType, channelName,
- (ClientData) infoPtr, infoPtr->validMask);
+ infoPtr, infoPtr->validMask);
/*
* Pipes have AUTO translation mode on Windows and ^Z eof char, which
@@ -1736,16 +1642,58 @@ TclpCreateCommandChannel(
* Windows programs that expect a ^Z at EOF.
*/
- Tcl_SetChannelOption((Tcl_Interp *) NULL, infoPtr->channel,
- "-translation", "auto");
- Tcl_SetChannelOption((Tcl_Interp *) NULL, infoPtr->channel,
- "-eofchar", "\032 {}");
+ Tcl_SetChannelOption(NULL, infoPtr->channel, "-translation", "auto");
+ Tcl_SetChannelOption(NULL, infoPtr->channel, "-eofchar", "\032 {}");
return infoPtr->channel;
}
/*
*----------------------------------------------------------------------
*
+ * Tcl_CreatePipe --
+ *
+ * System dependent interface to create a pipe for the [chan pipe]
+ * command. Stolen from TclX.
+ *
+ * Results:
+ * TCL_OK or TCL_ERROR.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Tcl_CreatePipe(
+ Tcl_Interp *interp, /* Errors returned in result.*/
+ Tcl_Channel *rchan, /* Where to return the read side. */
+ Tcl_Channel *wchan, /* Where to return the write side. */
+ int flags) /* Reserved for future use. */
+{
+ HANDLE readHandle, writeHandle;
+ SECURITY_ATTRIBUTES sec;
+
+ sec.nLength = sizeof(SECURITY_ATTRIBUTES);
+ sec.lpSecurityDescriptor = NULL;
+ sec.bInheritHandle = FALSE;
+
+ if (!CreatePipe(&readHandle, &writeHandle, &sec, 0)) {
+ TclWinConvertError(GetLastError());
+ Tcl_AppendResult(interp, "pipe creation failed: ",
+ Tcl_PosixError(interp), NULL);
+ return TCL_ERROR;
+ }
+
+ *rchan = Tcl_MakeFileChannel((ClientData) readHandle, TCL_READABLE);
+ Tcl_RegisterChannel(interp, *rchan);
+
+ *wchan = Tcl_MakeFileChannel((ClientData) writeHandle, TCL_WRITABLE);
+ Tcl_RegisterChannel(interp, *wchan);
+
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* TclGetAndDetachPids --
*
* Stores a list of the command PIDs for a command channel in the
@@ -1786,7 +1734,7 @@ TclGetAndDetachPids(
Tcl_DetachPids(1, &(pipePtr->pidPtr[i]));
}
if (pipePtr->numPids > 0) {
- ckfree((char *) pipePtr->pidPtr);
+ ckfree(pipePtr->pidPtr);
pipePtr->numPids = 0;
}
}
@@ -2046,12 +1994,11 @@ PipeClose2Proc(
*/
if (pipePtr->errorFile) {
- WinFile *filePtr;
+ WinFile *filePtr = (WinFile *) pipePtr->errorFile;
- filePtr = (WinFile*)pipePtr->errorFile;
errChan = Tcl_MakeFileChannel((ClientData) filePtr->handle,
TCL_READABLE);
- ckfree((char *) filePtr);
+ ckfree(filePtr);
} else {
errChan = NULL;
}
@@ -2061,14 +2008,14 @@ PipeClose2Proc(
}
if (pipePtr->numPids > 0) {
- ckfree((char *) pipePtr->pidPtr);
+ ckfree(pipePtr->pidPtr);
}
if (pipePtr->writeBuf != NULL) {
ckfree(pipePtr->writeBuf);
}
- ckfree((char*) pipePtr);
+ ckfree(pipePtr);
if (errorCode == 0) {
return result;
@@ -2236,7 +2183,7 @@ PipeOutputProc(
ckfree(infoPtr->writeBuf);
}
infoPtr->writeBufLen = toWrite;
- infoPtr->writeBuf = ckalloc((unsigned int) toWrite);
+ infoPtr->writeBuf = ckalloc(toWrite);
}
memcpy(infoPtr->writeBuf, buf, (size_t) toWrite);
infoPtr->toWrite = toWrite;
@@ -2618,7 +2565,7 @@ Tcl_WaitPid(
*/
CloseHandle(infoPtr->hProcess);
- ckfree((char*)infoPtr);
+ ckfree(infoPtr);
return result;
}
@@ -2644,9 +2591,9 @@ Tcl_WaitPid(
void
TclWinAddProcess(
void *hProcess, /* Handle to process */
- unsigned long id) /* Global process identifier */
+ unsigned long id) /* Global process identifier */
{
- ProcInfo *procPtr = (ProcInfo *) ckalloc(sizeof(ProcInfo));
+ ProcInfo *procPtr = ckalloc(sizeof(ProcInfo));
PipeInit();
@@ -3105,6 +3052,100 @@ PipeThreadActionProc(
}
/*
+ *----------------------------------------------------------------------
+ *
+ * TclpOpenTemporaryFile --
+ *
+ * Creates a temporary file, possibly based on the supplied bits and
+ * pieces of template supplied in the first three arguments. If the
+ * fourth argument is non-NULL, it contains a Tcl_Obj to store the name
+ * of the temporary file in (and it is caller's responsibility to clean
+ * up). If the fourth argument is NULL, try to arrange for the temporary
+ * file to go away once it is no longer needed.
+ *
+ * Results:
+ * A read-write Tcl Channel open on the file.
+ *
+ *----------------------------------------------------------------------
+ */
+
+Tcl_Channel
+TclpOpenTemporaryFile(
+ Tcl_Obj *dirObj,
+ Tcl_Obj *basenameObj,
+ Tcl_Obj *extensionObj,
+ Tcl_Obj *resultingNameObj)
+{
+ TCHAR name[MAX_PATH];
+ char *namePtr;
+ HANDLE handle;
+ DWORD flags = FILE_ATTRIBUTE_TEMPORARY;
+ int length, counter, counter2;
+ Tcl_DString buf;
+
+ if (!resultingNameObj) {
+ flags |= FILE_FLAG_DELETE_ON_CLOSE;
+ }
+
+ namePtr = (char *) name;
+ length = GetTempPath(MAX_PATH, name);
+ if (length == 0) {
+ goto gotError;
+ }
+ namePtr += length * sizeof(TCHAR);
+ if (basenameObj) {
+ const char *string = Tcl_GetStringFromObj(basenameObj, &length);
+
+ Tcl_WinUtfToTChar(string, length, &buf);
+ memcpy(namePtr, Tcl_DStringValue(&buf), Tcl_DStringLength(&buf));
+ namePtr += Tcl_DStringLength(&buf);
+ Tcl_DStringFree(&buf);
+ } else {
+ TCHAR *baseStr = TEXT("TCL");
+ int length = 3 * sizeof(TCHAR);
+
+ memcpy(namePtr, baseStr, length);
+ namePtr += length;
+ }
+ counter = TclpGetClicks() % 65533;
+ counter2 = 1024; /* Only try this many times! Prevents
+ * an infinite loop. */
+
+ do {
+ char number[TCL_INTEGER_SPACE + 4];
+
+ sprintf(number, "%d.TMP", counter);
+ counter = (unsigned short) (counter + 1);
+ Tcl_WinUtfToTChar(number, strlen(number), &buf);
+ Tcl_DStringSetLength(&buf, Tcl_DStringLength(&buf) + 1);
+ memcpy(namePtr, Tcl_DStringValue(&buf), Tcl_DStringLength(&buf) + 1);
+ Tcl_DStringFree(&buf);
+
+ handle = CreateFile(name,
+ GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW, flags, NULL);
+ } while (handle == INVALID_HANDLE_VALUE
+ && --counter2 > 0
+ && GetLastError() == ERROR_FILE_EXISTS);
+ if (handle == INVALID_HANDLE_VALUE) {
+ goto gotError;
+ }
+
+ if (resultingNameObj) {
+ Tcl_Obj *tmpObj = TclpNativeToNormalized(name);
+
+ Tcl_AppendObjToObj(resultingNameObj, tmpObj);
+ TclDecrRefCount(tmpObj);
+ }
+
+ return Tcl_MakeFileChannel((ClientData) handle,
+ TCL_READABLE|TCL_WRITABLE);
+
+ gotError:
+ TclWinConvertError(GetLastError());
+ return NULL;
+}
+
+/*
* Local Variables:
* mode: c
* c-basic-offset: 4