2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) INRIA - Allan CORNET
4 * Copyright (C) DIGITEO - 2010 - Allan CORNET
6 * This file must be used under the terms of the CeCILL.
7 * This source file is licensed as described in the file COPYING, which
8 * you should have received as part of this distribution. The terms
9 * are also available at
10 * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
14 /*--------------------------------------------------------------------------*/
17 #include "sci_malloc.h"
18 #include "FileExist.h"
19 #include "configvariable_interface.h"
20 #include "sci_tmpdir.h"
21 #include "spawncommand.h"
22 #include "os_string.h"
23 #include "charEncoding.h"
24 #include "getshortpathname.h"
25 #include "os_string.h"
26 /*--------------------------------------------------------------------------*/
32 #define NOTPRINTABLE -96
33 #define EMPTY_CHAR L'\0'
34 #define CMDLINE_FORMAT_DETACHED L"%ls /A /C \"%ls\""
35 #define CMDLINE_FORMAT_NOTDETACHED L"%ls /A /C \"%ls && echo DOS > %ls\""
36 #define OUTPUT_CHECK_FILENAME_FORMAT L"%ls\\DOS.OK"
37 /*--------------------------------------------------------------------------*/
38 pipeinfo SCILAB_WINDOWS_IMPEXP pipeSpawnOut = {INVALID_HANDLE_VALUE, NULL, 0};
39 pipeinfo SCILAB_WINDOWS_IMPEXP pipeSpawnErr = {INVALID_HANDLE_VALUE, NULL, 0};
40 /*--------------------------------------------------------------------------*/
41 static int GetNumberOfLines(char *lines);
42 static BOOL removeEOL(char *_string);
43 static BOOL removeNotPrintableCharacters(char *_string);
44 static char *convertLine(char *_string, BOOL DetachProcess);
45 /*--------------------------------------------------------------------------*/
46 int spawncommand(wchar_t *command, BOOL DetachProcess)
48 wchar_t shellCmd[PATH_MAX];
49 wchar_t *CmdLine = NULL;
52 PROCESS_INFORMATION pi;
53 SECURITY_ATTRIBUTES sa;
55 DWORD dwCreationFlags;
57 HANDLE hProcess = NULL, h = NULL, pipeThreads[2];
60 if (wcscmp(command, L"") == 0)
63 pipeSpawnOut.NumberOfLines = 0;
64 pipeSpawnOut.OutputBuffer = NULL;
66 pipeSpawnErr.NumberOfLines = 0;
67 pipeSpawnErr.OutputBuffer = NULL;
72 hProcess = GetCurrentProcess();
74 ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
75 ZeroMemory(&si, sizeof(STARTUPINFOW));
76 si.cb = sizeof(STARTUPINFO);
77 si.dwFlags = STARTF_USESTDHANDLES;
78 si.hStdInput = INVALID_HANDLE_VALUE;
80 ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
81 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
82 sa.lpSecurityDescriptor = NULL;
83 sa.bInheritHandle = TRUE;
85 /* create a non-inheritible pipe. */
86 CreatePipe(&pipeSpawnOut.pipe, &h, &sa, 0);
88 /* dupe the write side, make it inheritible, and close the original. */
89 DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput,
90 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
92 /* Same as above, but for the error side. */
93 CreatePipe(&pipeSpawnErr.pipe, &h, &sa, 0);
94 DuplicateHandle(hProcess, h, hProcess, &si.hStdError,
95 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
97 /* base command line */
98 GetEnvironmentVariableW(L"ComSpec", shellCmd, PATH_MAX);
102 int lenCmdLine = (int)(wcslen(shellCmd) + wcslen(command) + wcslen(CMDLINE_FORMAT_DETACHED));
103 CmdLine = (wchar_t*) MALLOC((lenCmdLine + 1) * sizeof(wchar_t));
104 os_swprintf(CmdLine, lenCmdLine, CMDLINE_FORMAT_DETACHED, shellCmd, command);
106 dwCreationFlags = DETACHED_PROCESS;
111 wchar_t FileTMPDir[PATH_MAX + 16];
112 BOOL bConvert = FALSE;
114 wchar_t *TMPDirLong = getTMPDIRW();
116 os_swprintf(FileTMPDir, PATH_MAX + 16, OUTPUT_CHECK_FILENAME_FORMAT, TMPDirLong);
119 if (FileExistW(FileTMPDir))
121 DeleteFileW(FileTMPDir);
124 lenCmdLine = (int)(wcslen(shellCmd) + wcslen(command) + wcslen(CMDLINE_FORMAT_NOTDETACHED) +
126 CmdLine = (wchar_t*)MALLOC((lenCmdLine + 1) * sizeof(wchar_t));
127 os_swprintf(CmdLine, lenCmdLine, CMDLINE_FORMAT_NOTDETACHED, shellCmd, command, FileTMPDir);
133 NULL, /* Module name. */
134 CmdLine, /* Command line. */
135 NULL, /* Process handle not inheritable. */
136 NULL, /* Thread handle not inheritable. */
137 TRUE, /* yes, inherit handles. */
138 dwCreationFlags, /* No console for you. */
139 NULL, /* Use parent's environment block. */
140 NULL, /* Use parent's starting directory. */
141 &si, /* Pointer to STARTUPINFO structure. */
142 &pi); /* Pointer to PROCESS_INFORMATION structure. */
155 /* close our references to the write handles that have now been inherited. */
156 CloseHandle(si.hStdOutput);
157 CloseHandle(si.hStdError);
159 WaitForInputIdle(pi.hProcess, 5000);
160 CloseHandle(pi.hThread);
162 /* start the pipe reader threads. */
163 pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &pipeSpawnOut, 0, &threadID);
164 pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &pipeSpawnErr, 0, &threadID);
166 /* block waiting for the process to end. */
167 WaitForSingleObject(pi.hProcess, INFINITE);
169 if ( GetExitCodeProcess(pi.hProcess, &ExitCode) == STILL_ACTIVE )
171 TerminateProcess(pi.hProcess, 0);
174 CloseHandle(pi.hProcess);
176 /* wait for our pipe to get done reading */
177 WaitForMultipleObjects(2, pipeThreads, TRUE, 500);
178 CloseHandle(pipeThreads[0]);
179 CloseHandle(pipeThreads[1]);
183 /*--------------------------------------------------------------------------*/
184 int ClosePipeInfo (pipeinfo pipe)
186 CloseHandle(pipe.pipe);
187 if (pipe.OutputBuffer)
189 FREE(pipe.OutputBuffer);
190 pipe.OutputBuffer = NULL;
191 pipe.NumberOfLines = 0;
195 /*--------------------------------------------------------------------------*/
196 DWORD WINAPI ReadFromPipe (LPVOID args)
198 pipeinfo *pi = (pipeinfo *) args;
201 BOOL moreOutput = TRUE;
202 unsigned char *op = NULL;
204 pi->OutputBuffer = (unsigned char*) MALLOC(BUFSIZE);
205 op = pi->OutputBuffer;
209 BOOL bres = ReadFile( pi->pipe, op, BUFSIZE - 1, &dwRead, NULL);
211 moreOutput = bres || (dwRead != 0);
216 pi->OutputBuffer = (unsigned char*) REALLOC(pi->OutputBuffer , readSoFar + BUFSIZE);
217 op = pi->OutputBuffer + readSoFar;
223 /*--------------------------------------------------------------------------*/
224 int GetNumberOfLines(char *lines)
226 int NumberOfLines = 0;
229 char *buffer = os_strdup(lines);
233 char *line = strtok(buffer, LF_STR);
237 line = strtok(NULL, LF_STR);
246 if (NumberOfLines == 0)
251 return NumberOfLines;
253 /*--------------------------------------------------------------------------*/
254 char **CreateOuput(pipeinfo *pipe, BOOL DetachProcess)
256 char **OuputStrings = NULL;
259 if (pipe->OutputBuffer)
261 char *buffer = os_strdup(pipe->OutputBuffer);
264 pipe->NumberOfLines = GetNumberOfLines(buffer);
265 if (pipe->NumberOfLines)
267 OuputStrings = (char**)MALLOC((pipe->NumberOfLines) * sizeof(char*));
268 memset(OuputStrings, 0x00, sizeof(char*) * pipe->NumberOfLines);
271 char *line = strtok(buffer, LF_STR);
276 OuputStrings[i] = convertLine(line, DetachProcess);
277 line = strtok(NULL, LF_STR);
279 if (i > pipe->NumberOfLines)
293 /*--------------------------------------------------------------------------*/
294 BOOL DetectDetachProcessInCommandLine(wchar_t *command)
299 int i = (int)wcslen(command);
300 for (i = (int)wcslen(command) - 1; i >= 0; i--)
302 if (command[i] == BLANK)
304 command[i] = EMPTY_CHAR;
311 i = (int)wcslen(command);
312 if ( (i > 0) && (command[i - 1] == L'&') )
319 /*--------------------------------------------------------------------------*/
320 BOOL removeEOL(char *_string)
324 int len = (int)strlen(_string);
325 if ( (_string[len - 1] == CR) || (_string[len - 1] == LF) )
327 _string[len - 1] = EMPTY_CHAR;
333 /*--------------------------------------------------------------------------*/
334 BOOL removeNotPrintableCharacters(char *_string)
339 int len = (int)strlen(_string);
340 BOOL bRemove = FALSE;
341 for (j = 0; j < len; j++)
343 /* remove some no printable characters */
344 if (_string[j] == NOTPRINTABLE)
354 /*--------------------------------------------------------------------------*/
355 char *convertLine(char *_string, BOOL DetachProcess)
357 char *convertedString = NULL;
360 convertedString = os_strdup(_string);
362 if (getScilabMode() == SCILAB_STD)
364 if ( (!DetachProcess) && (!IsValidUTF8(_string)) )
366 // We need to add detection of ANSI characters
367 // in this case we do not convert from Oem to char
368 OemToChar(_string, convertedString);
374 // chcp 65001 (to switch cmd to UNICODE)
375 // and change font to Lucida (TrueType)
376 if ( (DetachProcess) && (!IsValidUTF8(_string)) )
378 CharToOem(_string, convertedString);
382 removeEOL(convertedString);
383 removeNotPrintableCharacters(convertedString);
386 return convertedString;
388 /*--------------------------------------------------------------------------*/
389 int CallWindowsShell(char *command)
391 int returnedExitCode = -1;
393 wchar_t shellCmd[PATH_MAX];
394 wchar_t *CmdLine = NULL;
395 wchar_t * wcommand = NULL;
398 PROCESS_INFORMATION piProcInfo;
399 STARTUPINFOW siStartInfo;
400 SECURITY_ATTRIBUTES saAttr;
404 wchar_t *TMPDir = NULL;
405 wchar_t FileTMPDir[PATH_MAX];
407 if (strcmp(command, "") == 0)
413 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
414 saAttr.bInheritHandle = TRUE;
415 saAttr.lpSecurityDescriptor = NULL;
417 ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
419 ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
420 siStartInfo.cb = sizeof(STARTUPINFO);
421 siStartInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
422 siStartInfo.wShowWindow = SW_HIDE;
423 siStartInfo.hStdInput = NULL;
425 siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
426 siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
428 GetEnvironmentVariableW(L"ComSpec", shellCmd, PATH_MAX);
429 TMPDir = getTMPDIRW();
430 os_swprintf(FileTMPDir, PATH_MAX, L"%ls\\DOS.OK", TMPDir);
437 wcommand = to_wide_string(command);
438 iCmdSize = (wcslen(shellCmd) + wcslen(wcommand) + wcslen(FileTMPDir) + wcslen(L"%ls /a /c \"%ls\" && echo DOS>%ls") + 1);
439 CmdLine = (wchar_t*)MALLOC(iCmdSize * sizeof(wchar_t));
440 os_swprintf(CmdLine, iCmdSize, L"%ls /a /c \"%ls\" && echo DOS>%ls", shellCmd, wcommand, FileTMPDir);
442 if (CreateProcessW(NULL, CmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &siStartInfo, &piProcInfo))
444 WaitForSingleObject(piProcInfo.hProcess, INFINITE);
446 if ( GetExitCodeProcess(piProcInfo.hProcess, &ExitCode) == STILL_ACTIVE )
448 TerminateProcess(piProcInfo.hProcess, 0);
451 CloseHandle(piProcInfo.hProcess);
459 if (FileExistW(FileTMPDir))
461 DeleteFileW(FileTMPDir);
464 returnedExitCode = (int)ExitCode;
468 CloseHandle(piProcInfo.hProcess);
475 return returnedExitCode;
477 /*--------------------------------------------------------------------------*/
478 int CallWindowsShellW(wchar_t* _pstCommand)
480 int returnedExitCode = -1;
482 wchar_t shellCmd[PATH_MAX];
483 wchar_t *CmdLine = NULL;
486 PROCESS_INFORMATION piProcInfo;
487 STARTUPINFOW siStartInfo;
488 SECURITY_ATTRIBUTES saAttr;
492 wchar_t *TMPDir = NULL;
493 wchar_t FileTMPDir[PATH_MAX];
495 if (wcscmp(_pstCommand, L"") == 0)
501 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
502 saAttr.bInheritHandle = TRUE;
503 saAttr.lpSecurityDescriptor = NULL;
505 ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));
507 ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
508 siStartInfo.cb = sizeof(STARTUPINFO);
509 siStartInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
510 siStartInfo.wShowWindow = SW_HIDE;
511 siStartInfo.hStdInput = NULL;
513 siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
514 siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
516 GetEnvironmentVariableW(L"ComSpec", shellCmd, PATH_MAX);
517 TMPDir = getTMPDIRW();
518 os_swprintf(FileTMPDir, PATH_MAX, L"%ls\\DOS.OK", TMPDir);
525 iCmdSize = (wcslen(shellCmd) + wcslen(_pstCommand) + wcslen(FileTMPDir) + wcslen(L"%ls /a /c \"%ls\" && echo DOS>%ls") + 1);
526 CmdLine = (wchar_t*)MALLOC(iCmdSize * sizeof(wchar_t));
527 os_swprintf(CmdLine, iCmdSize, L"%ls /a /c \"%ls\" && echo DOS>%ls", shellCmd, _pstCommand, FileTMPDir);
529 if (CreateProcessW(NULL, CmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &siStartInfo, &piProcInfo))
531 WaitForSingleObject(piProcInfo.hProcess, INFINITE);
533 if (GetExitCodeProcess(piProcInfo.hProcess, &ExitCode) == STILL_ACTIVE)
535 TerminateProcess(piProcInfo.hProcess, 0);
538 CloseHandle(piProcInfo.hProcess);
546 if (FileExistW(FileTMPDir))
548 DeleteFileW(FileTMPDir);
551 returnedExitCode = (int)ExitCode;
555 CloseHandle(piProcInfo.hProcess);
562 return returnedExitCode;
564 /*--------------------------------------------------------------------------*/