The R Project SVN R

Rev

Rev 52813 | Rev 52836 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 52813 Rev 52814
Line 39... Line 39...
39
{
39
{
40
    char  c;
40
    char  c;
41
    char *s, *p, *q, *f, *dest, *src;
41
    char *s, *p, *q, *f, *dest, *src;
42
    int   d, ext, len = strlen(cmd)+1;
42
    int   d, ext, len = strlen(cmd)+1;
43
    char buf[len], fl[len], fn[len];
43
    char buf[len], fl[len], fn[len];
44
	  
44
 
45
    /* make a copy as we manipulate in place */
45
    /* make a copy as we manipulate in place */
46
    strcpy(buf, cmd);
46
    strcpy(buf, cmd);
47
 
47
 
48
    if (!(s = (char *) malloc(MAX_PATH + strlen(cmd)))) {
48
    if (!(s = (char *) malloc(MAX_PATH + strlen(cmd)))) {
49
	strcpy(RunError, "Insufficient memory (expandcmd)");
49
	strcpy(RunError, "Insufficient memory (expandcmd)");
Line 119... Line 119...
119
   with the hThread handle closed.
119
   with the hThread handle closed.
120
*/
120
*/
121
 
121
 
122
extern size_t Rf_utf8towcs(wchar_t *wc, const char *s, size_t n);
122
extern size_t Rf_utf8towcs(wchar_t *wc, const char *s, size_t n);
123
 
123
 
124
static void pcreate(const char* cmd, cetype_t enc, 
124
static void pcreate(const char* cmd, cetype_t enc,
125
		      int newconsole, int visible, 
125
		      int newconsole, int visible,
126
		      HANDLE hIN, HANDLE hOUT, HANDLE hERR,
126
		      HANDLE hIN, HANDLE hOUT, HANDLE hERR,
127
		      PROCESS_INFORMATION *pi)
127
		      PROCESS_INFORMATION *pi)
128
{
128
{
129
    DWORD ret;
129
    DWORD ret;
130
    STARTUPINFO si;
130
    STARTUPINFO si;
Line 139... Line 139...
139
    sa.bInheritHandle = TRUE;
139
    sa.bInheritHandle = TRUE;
140
 
140
 
141
    /* FIXME: this might need to be done in wchar_t */
141
    /* FIXME: this might need to be done in wchar_t */
142
    if (!(ecmd = expandcmd(cmd))) return; /* error message already set */
142
    if (!(ecmd = expandcmd(cmd))) return; /* error message already set */
143
 
143
 
144
    inpipe = (hIN != INVALID_HANDLE_VALUE) 
144
    inpipe = (hIN != INVALID_HANDLE_VALUE)
145
	|| (hOUT != INVALID_HANDLE_VALUE) 
145
	|| (hOUT != INVALID_HANDLE_VALUE)
146
	|| (hERR != INVALID_HANDLE_VALUE);
146
	|| (hERR != INVALID_HANDLE_VALUE);
147
 
147
 
148
    if (inpipe) {         
148
    if (inpipe) {
149
	HANDLE hNULL = CreateFile("NUL:", GENERIC_READ | GENERIC_WRITE, 0, 
149
	HANDLE hNULL = CreateFile("NUL:", GENERIC_READ | GENERIC_WRITE, 0,
150
			   &sa, OPEN_EXISTING, 0, NULL);
150
			   &sa, OPEN_EXISTING, 0, NULL);
151
    	HANDLE hTHIS = GetCurrentProcess();			   
151
	HANDLE hTHIS = GetCurrentProcess();
152
 
152
 
153
	if (hIN == INVALID_HANDLE_VALUE) hIN = hNULL;
153
	if (hIN == INVALID_HANDLE_VALUE) hIN = hNULL;
154
	if (hOUT == INVALID_HANDLE_VALUE) hOUT = hNULL;
154
	if (hOUT == INVALID_HANDLE_VALUE) hOUT = hNULL;
155
	if (hERR == INVALID_HANDLE_VALUE) hERR = hNULL;
155
	if (hERR == INVALID_HANDLE_VALUE) hERR = hNULL;
156
	
156
 
157
	DuplicateHandle(hTHIS, hIN,
157
	DuplicateHandle(hTHIS, hIN,
158
			hTHIS, &dupIN, 0, TRUE, DUPLICATE_SAME_ACCESS);
158
			hTHIS, &dupIN, 0, TRUE, DUPLICATE_SAME_ACCESS);
159
	DuplicateHandle(hTHIS, hOUT,
159
	DuplicateHandle(hTHIS, hOUT,
160
			hTHIS, &dupOUT, 0, TRUE, DUPLICATE_SAME_ACCESS);
160
			hTHIS, &dupOUT, 0, TRUE, DUPLICATE_SAME_ACCESS);
161
	DuplicateHandle(hTHIS, hERR,
161
	DuplicateHandle(hTHIS, hERR,
162
			hTHIS, &dupERR, 0, TRUE, DUPLICATE_SAME_ACCESS);
162
			hTHIS, &dupERR, 0, TRUE, DUPLICATE_SAME_ACCESS);
163
	CloseHandle(hTHIS);
163
	CloseHandle(hTHIS);
164
	CloseHandle(hNULL);
164
	CloseHandle(hNULL);
165
    }   
165
    }
166
    
166
 
167
    switch (visible) {
167
    switch (visible) {
168
    case -1:
168
    case -1:
169
	showWindow = SW_HIDE;
169
	showWindow = SW_HIDE;
170
	break;
170
	break;
171
    case 0:
171
    case 0:
172
	showWindow = SW_SHOWMINIMIZED;
172
	showWindow = SW_SHOWMINIMIZED;
173
	break;
173
	break;
174
    }
174
    }
175
    
175
 
176
    if(enc == CE_UTF8) {
176
    if(enc == CE_UTF8) {
177
	wsi.cb = sizeof(wsi);
177
	wsi.cb = sizeof(wsi);
178
	wsi.lpReserved = NULL;
178
	wsi.lpReserved = NULL;
179
	wsi.lpReserved2 = NULL;
179
	wsi.lpReserved2 = NULL;
180
	wsi.cbReserved2 = 0;
180
	wsi.cbReserved2 = 0;
181
	wsi.lpDesktop = NULL;
181
	wsi.lpDesktop = NULL;
182
	wsi.lpTitle = NULL;
182
	wsi.lpTitle = NULL;
183
	wsi.dwFlags = STARTF_USESHOWWINDOW;
183
	wsi.dwFlags = STARTF_USESHOWWINDOW;
184
	wsi.wShowWindow = showWindow;	
184
	wsi.wShowWindow = showWindow;
185
	if (inpipe) {
185
	if (inpipe) {
186
	    wsi.dwFlags |= STARTF_USESTDHANDLES;
186
	    wsi.dwFlags |= STARTF_USESTDHANDLES;
187
	    wsi.hStdInput  = dupIN;
187
	    wsi.hStdInput  = dupIN;
188
	    wsi.hStdOutput = dupOUT;
188
	    wsi.hStdOutput = dupOUT;
189
	    wsi.hStdError  = dupERR;
189
	    wsi.hStdError  = dupERR;
Line 194... Line 194...
194
	si.lpReserved2 = NULL;
194
	si.lpReserved2 = NULL;
195
	si.cbReserved2 = 0;
195
	si.cbReserved2 = 0;
196
	si.lpDesktop = NULL;
196
	si.lpDesktop = NULL;
197
	si.lpTitle = NULL;
197
	si.lpTitle = NULL;
198
	si.dwFlags = STARTF_USESHOWWINDOW;
198
	si.dwFlags = STARTF_USESHOWWINDOW;
199
	si.wShowWindow = showWindow;	
199
	si.wShowWindow = showWindow;
200
	if (inpipe) {
200
	if (inpipe) {
201
	    si.dwFlags |= STARTF_USESTDHANDLES;
201
	    si.dwFlags |= STARTF_USESTDHANDLES;
202
	    si.hStdInput  = dupIN;
202
	    si.hStdInput  = dupIN;
203
	    si.hStdOutput = dupOUT;
203
	    si.hStdOutput = dupOUT;
204
	    si.hStdError  = dupERR;
204
	    si.hStdError  = dupERR;
Line 258... Line 258...
258
char *runerror(void)
258
char *runerror(void)
259
{
259
{
260
    return RunError;
260
    return RunError;
261
}
261
}
262
 
262
 
263
static HANDLE getInputHandle(const char *finput)
263
static HANDLE getInputHandle(const char *fin)
264
{
264
{
265
    if (finput && finput[0]) {
265
    if (fin && fin[0]) {
266
	SECURITY_ATTRIBUTES sa;
266
	SECURITY_ATTRIBUTES sa;
267
	sa.nLength = sizeof(sa);
267
	sa.nLength = sizeof(sa);
268
	sa.lpSecurityDescriptor = NULL;
268
	sa.lpSecurityDescriptor = NULL;
269
	sa.bInheritHandle = TRUE;    
269
	sa.bInheritHandle = TRUE;
270
	HANDLE hIN = CreateFile(finput, GENERIC_READ, 0,
270
	HANDLE hIN = CreateFile(fin, GENERIC_READ, 0,
271
			 &sa, OPEN_EXISTING, 0, NULL);
271
				&sa, OPEN_EXISTING, 0, NULL);
272
	if (hIN == INVALID_HANDLE_VALUE) {
272
	if (hIN == INVALID_HANDLE_VALUE) {
-
 
273
	    snprintf(RunError, 500, 
273
	    strcpy(RunError, _("unable to redirect input"));
274
		     "unable to redirect input from '%s'", fin);
274
	    return NULL;
275
	    return NULL;
275
	}
276
	}
276
	return hIN;
277
	return hIN;
277
    }
278
    }
278
    return INVALID_HANDLE_VALUE;
279
    return INVALID_HANDLE_VALUE;
279
}
280
}
280
 
281
 
-
 
282
static HANDLE getOutputHandle(const char *fout)
-
 
283
{
-
 
284
    if (fout && fout[0]) {
-
 
285
	SECURITY_ATTRIBUTES sa;
-
 
286
	sa.nLength = sizeof(sa);
-
 
287
	sa.lpSecurityDescriptor = NULL;
-
 
288
	sa.bInheritHandle = TRUE;
-
 
289
	HANDLE hOUT = CreateFile(fout, GENERIC_WRITE, 0,
-
 
290
				 &sa, CREATE_ALWAYS, 0, NULL);
-
 
291
	if (hOUT == INVALID_HANDLE_VALUE) {
-
 
292
	    snprintf(RunError, 500, 
-
 
293
		     "unable to redirect output to '%s'", fout);
-
 
294
	    return NULL;
-
 
295
	}
-
 
296
	return hOUT;
-
 
297
    }
-
 
298
    return INVALID_HANDLE_VALUE;
-
 
299
}
-
 
300
 
281
BOOL CALLBACK TerminateWindow(HWND hwnd, LPARAM lParam)
301
BOOL CALLBACK TerminateWindow(HWND hwnd, LPARAM lParam)
282
{
302
{
283
    DWORD ID ;
303
    DWORD ID ;
284
 
304
 
285
    GetWindowThreadProcessId(hwnd, &ID);
305
    GetWindowThreadProcessId(hwnd, &ID);
286
 
306
 
287
    if (ID == (DWORD)lParam)
307
    if (ID == (DWORD)lParam)
288
        PostMessage(hwnd, WM_CLOSE, 0, 0);
308
	PostMessage(hwnd, WM_CLOSE, 0, 0);
289
    return TRUE;
309
    return TRUE;
290
}
310
}
291
 
311
 
292
/* Terminate the process pwait2 is waiting for. */
312
/* Terminate the process pwait2 is waiting for. */
293
 
313
 
Line 295... Line 315...
295
 
315
 
296
static void terminate_process(void *p)
316
static void terminate_process(void *p)
297
{
317
{
298
    PROCESS_INFORMATION *pi = (PROCESS_INFORMATION*)p;
318
    PROCESS_INFORMATION *pi = (PROCESS_INFORMATION*)p;
299
    EnumWindows((WNDENUMPROC)TerminateWindow, (LPARAM)pi->dwProcessId);
319
    EnumWindows((WNDENUMPROC)TerminateWindow, (LPARAM)pi->dwProcessId);
300
    
320
 
301
    if (WaitForSingleObject(pi->hProcess, 5000) == WAIT_TIMEOUT) {
321
    if (WaitForSingleObject(pi->hProcess, 5000) == WAIT_TIMEOUT) {
302
    	if (R_Interactive)
322
	if (R_Interactive)
303
    	    GA_askok(_("Child process not responding.  R will terminate it."));
323
	    GA_askok(_("Child process not responding.  R will terminate it."));
304
    	TerminateProcess(pi->hProcess, 99);
324
	TerminateProcess(pi->hProcess, 99);
305
    }
325
    }
306
}
326
}
307
 
327
 
308
static int pwait2(HANDLE p)
328
static int pwait2(HANDLE p)
309
{
329
{
310
    DWORD ret;
330
    DWORD ret;
311
 
331
 
312
    while( WaitForSingleObject(p, 100) == WAIT_TIMEOUT ) 
332
    while( WaitForSingleObject(p, 100) == WAIT_TIMEOUT )
313
    	R_CheckUserInterrupt();
333
	R_CheckUserInterrupt();
314
    	
334
 
315
    GetExitCodeProcess(p, &ret);
335
    GetExitCodeProcess(p, &ret);
316
    return ret;
336
    return ret;
317
}
337
}
318
 
338
 
319
/*
339
/*
320
  Used for external commands in file.show() and edit(), and for
340
  Used for external commands in file.show() and edit(), and for
321
  system(intern=FALSE).
341
  system(intern=FALSE).  Also called from postscript().
322
 
342
 
323
  wait != 0 says wait for child to terminate before returning.
343
  wait != 0 says wait for child to terminate before returning.
324
  visible = -1, 0, 1 for hide, minimized, default
344
  visible = -1, 0, 1 for hide, minimized, default
325
  finput is either NULL or the name of a file from which to
345
  fin is either NULL or the name of a file from which to
326
  redirect stdin for the child.
346
  redirect stdin for the child.
327
*/
347
*/
328
int runcmd(const char *cmd, cetype_t enc, int wait, int visible, 
348
int runcmd(const char *cmd, cetype_t enc, int wait, int visible,
329
	   const char *finput)
349
	   const char *fin, const char *fout, const char *ferr)
330
{
350
{
331
    HANDLE hIN = getInputHandle(finput);
351
    HANDLE hIN = getInputHandle(fin), hOUT = getOutputHandle(fout),
-
 
352
	hERR = getOutputHandle(ferr);
332
    int ret = 0;
353
    int ret = 0;
333
    PROCESS_INFORMATION pi;
354
    PROCESS_INFORMATION pi;
334
 
355
 
335
    memset(&pi, 0, sizeof(pi));
356
    memset(&pi, 0, sizeof(pi));
336
    pcreate(cmd, enc, !wait, visible, 
357
    pcreate(cmd, enc, !wait, visible, hIN, hOUT, hERR, &pi);
337
    		      hIN,
-
 
338
    		      INVALID_HANDLE_VALUE,
-
 
339
    		      INVALID_HANDLE_VALUE,
-
 
340
    		      &pi); 
-
 
341
    if (!pi.hProcess) return NOLAUNCH;
358
    if (!pi.hProcess) return NOLAUNCH;
342
    if (wait) {
359
    if (wait) {
343
    	RCNTXT cntxt;
360
	RCNTXT cntxt;
344
    	begincontext(&cntxt, CTXT_CCODE, R_NilValue, R_BaseEnv, R_BaseEnv,
361
	begincontext(&cntxt, CTXT_CCODE, R_NilValue, R_BaseEnv, R_BaseEnv,
345
		 R_NilValue, R_NilValue);
362
		 R_NilValue, R_NilValue);
346
    	cntxt.cend = &terminate_process;
363
	cntxt.cend = &terminate_process;
347
    	cntxt.cenddata = π
364
	cntxt.cenddata = π
348
	ret = pwait2(pi.hProcess);
365
	ret = pwait2(pi.hProcess);
349
	endcontext(&cntxt);
366
	endcontext(&cntxt);
350
	sprintf(RunError, _("Exit code was %d"), ret);
367
	sprintf(RunError, _("Exit code was %d"), ret);
351
	ret &= 0xffff;
368
	ret &= 0xffff;
352
    } else ret = 0;
369
    } else ret = 0;
353
    CloseHandle(pi.hProcess);
370
    CloseHandle(pi.hProcess);
354
    if (hIN != INVALID_HANDLE_VALUE) CloseHandle(hIN);
371
    if (hIN != INVALID_HANDLE_VALUE) CloseHandle(hIN);
-
 
372
    if (hOUT != INVALID_HANDLE_VALUE) CloseHandle(hERR);
-
 
373
    if (hERR != INVALID_HANDLE_VALUE) CloseHandle(hERR);
355
    return ret;
374
    return ret;
356
}
375
}
357
 
376
 
358
/*
377
/*
359
   finput is either NULL or the name of a file from which to
378
   finput is either NULL or the name of a file from which to
360
     redirect stdin for the child.
379
     redirect stdin for the child.
361
   visible = -1, 0, 1 for hide, minimized, default
380
   visible = -1, 0, 1 for hide, minimized, default
362
   io = 0 to read stdout from pipe, 1 to write to pipe,
381
   io = 0 to read stdout from pipe, 1 to write to pipe,
-
 
382
   2 to read stderr from pipe, 
363
   2 to read stdout and stderr from pipe.
383
   3 to read both stdout and stderr from pipe.
364
 */
384
 */
365
rpipe * rpipeOpen(const char *cmd, cetype_t enc, int visible,
385
rpipe * rpipeOpen(const char *cmd, cetype_t enc, int visible,
366
		  const char *finput, int io)
386
		  const char *finput, int io)
367
{
387
{
368
    rpipe *r;
388
    rpipe *r;
Line 388... Line 408...
388
	r->read = hReadPipe;
408
	r->read = hReadPipe;
389
	DuplicateHandle(hTHIS, hWritePipe, hTHIS, &r->write,
409
	DuplicateHandle(hTHIS, hWritePipe, hTHIS, &r->write,
390
			0, FALSE, DUPLICATE_SAME_ACCESS);
410
			0, FALSE, DUPLICATE_SAME_ACCESS);
391
	CloseHandle(hWritePipe);
411
	CloseHandle(hWritePipe);
392
	CloseHandle(hTHIS);
412
	CloseHandle(hTHIS);
393
	pcreate(cmd, enc, 1, visible, 
413
	pcreate(cmd, enc, 1, visible,
394
	        r->read, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE,
414
		r->read, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE,
395
	        &(r->pi));
415
		&(r->pi));
396
	r->active = 1;
416
	r->active = 1;
397
	if (!r->pi.hProcess) return NULL; else return r;
417
	if (!r->pi.hProcess) return NULL; else return r;
398
    }
418
    }
399
    /* pipe for R to read from */
419
    /* pipe for R to read from */
400
    hTHIS = GetCurrentProcess();
420
    hTHIS = GetCurrentProcess();
401
    r->write = hWritePipe;
421
    r->write = hWritePipe;
402
    DuplicateHandle(hTHIS, hReadPipe, hTHIS, &r->read,
422
    DuplicateHandle(hTHIS, hReadPipe, hTHIS, &r->read,
403
		    0, FALSE, DUPLICATE_SAME_ACCESS);
423
		    0, FALSE, DUPLICATE_SAME_ACCESS);
404
    CloseHandle(hReadPipe);
424
    CloseHandle(hReadPipe);
405
    CloseHandle(hTHIS);
425
    CloseHandle(hTHIS);
406
    
426
 
407
    hIN = getInputHandle(finput);
427
    hIN = getInputHandle(finput);
408
    pcreate(cmd, enc, 0, visible, 
428
    pcreate(cmd, enc, 0, visible,
409
            hIN, r->write, 
429
	    hIN, 
-
 
430
	    (io == 0 || io == 3) ? r->write : INVALID_HANDLE_VALUE,
410
            io > 0 ? r->write : INVALID_HANDLE_VALUE,
431
	    io >= 2 ? r->write : INVALID_HANDLE_VALUE,
411
            &(r->pi));
432
	    &(r->pi));
412
    if (hIN != INVALID_HANDLE_VALUE) CloseHandle(hIN);
433
    if (hIN != INVALID_HANDLE_VALUE) CloseHandle(hIN);
413
    
434
 
414
    r->active = 1;
435
    r->active = 1;
415
    if (!r->pi.hProcess)
436
    if (!r->pi.hProcess)
416
	return NULL;
437
	return NULL;
417
    if (!(r->thread = CreateThread(NULL, 0, threadedwait, r, 0, &id))) {
438
    if (!(r->thread = CreateThread(NULL, 0, threadedwait, r, 0, &id))) {
418
	rpipeClose(r);
439
	rpipeClose(r);
Line 420... Line 441...
420
	return NULL;
441
	return NULL;
421
    }
442
    }
422
    return r;
443
    return r;
423
}
444
}
424
 
445
 
425
static void 
446
static void
426
rpipeTerminate(rpipe * r)
447
rpipeTerminate(rpipe * r)
427
{
448
{
428
    if (r->thread) {
449
    if (r->thread) {
429
        TerminateThread(r->thread, 0);
450
	TerminateThread(r->thread, 0);
430
        CloseHandle(r->thread);
451
	CloseHandle(r->thread);
431
        r->thread = NULL;
452
	r->thread = NULL;
432
    }
453
    }
433
    if (r->active) {
454
    if (r->active) {
434
    	terminate_process(&(r->pi));
455
	terminate_process(&(r->pi));
435
    	r->active = 0;
456
	r->active = 0;
436
    }
457
    }
437
}
458
}
438
 
459
 
439
#include "graphapp/ga.h"
460
#include "graphapp/ga.h"
440
extern Rboolean UserBreak;
461
extern Rboolean UserBreak;