The R Project SVN R

Rev

Rev 85539 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
4394 ripley 1
/*
2
 *  R : A Computer Language for Statistical Data Analysis
3
 *  file run.c: a simple 'reading' pipe (and a command executor)
64657 ripley 4
 *  Copyright  (C) 1999-2001  Guido Masarotto and Brian Ripley
83695 kalibera 5
 *             (C) 2007-2023  The R Core Team
4394 ripley 6
 *
7
 *  This program is free software; you can redistribute it and/or modify
8
 *  it under the terms of the GNU General Public License as published by
9
 *  the Free Software Foundation; either version 2 of the License, or
10
 *  (at your option) any later version.
11
 *
12
 *  This program is distributed in the hope that it will be useful,
13
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 *  GNU General Public License for more details.
16
 *
17
 *  You should have received a copy of the GNU General Public License
42300 ripley 18
 *  along with this program; if not, a copy is available at
68956 ripley 19
 *  https://www.R-project.org/Licenses/
5458 ripley 20
 */
4394 ripley 21
 
8872 pd 22
#ifdef HAVE_CONFIG_H
23
#include <config.h>
24
#endif
57538 ripley 25
 
26
#define R_USE_SIGNALS 1
40513 ripley 27
#include <Defn.h>
60667 ripley 28
#include <Internal.h>
32888 ripley 29
#include "win-nls.h"
4394 ripley 30
 
36901 ripley 31
#define WIN32_LEAN_AND_MEAN 1
4394 ripley 32
#include <windows.h>
82247 kalibera 33
#include <versionhelpers.h>
72855 kalibera 34
#include <mmsystem.h> /* for timeGetTime */
4394 ripley 35
#include <string.h>
36
#include <stdlib.h>
37
#include <ctype.h>
38
#include "run.h"
39
 
53870 murdoch 40
#include <Startup.h> /* for CharacterMode and RGui */
41
 
67837 murdoch 42
#include <trioremap.h>
43
 
42639 ripley 44
static char RunError[501] = "";
4394 ripley 45
 
85539 kalibera 46
static Rboolean hasspace(const char *s)
47
{
48
    if (!s)
49
	return FALSE;
50
    for(;*s;s++)
51
	if (isspace(*s)) return TRUE;
52
    return FALSE;
53
} 
54
 
59546 ripley 55
/* This might be given a command line (whole = 0) or just the
65574 ripley 56
   executable (whole = 1).  In the later case the path may or may not
85539 kalibera 57
   be quoted. 
58
 
59
   When whole = 0, the command will be quoted in the result if it contains
60
   space. */
59546 ripley 61
static char *expandcmd(const char *cmd, int whole)
4394 ripley 62
{
59546 ripley 63
    char c = '\0';
83695 kalibera 64
    char *s = NULL, *p, *q = NULL, *f, *dest, *src, *fn = NULL;
65
    int  ext, len = strlen(cmd)+1;
83756 kalibera 66
    char buf[len], fl[len + 4];
83695 kalibera 67
    DWORD d, res = 0;
52814 ripley 68
 
41793 ripley 69
    /* make a copy as we manipulate in place */
70
    strcpy(buf, cmd);
71
 
72
    /* skip leading spaces */
73
    for (p = buf; *p && isspace(*p); p++);
74
    /* find the command itself, possibly double-quoted */
59546 ripley 75
    if (whole) {
76
	d = 0;
65574 ripley 77
    } else { // command line
59546 ripley 78
	for (q = p, d = 0; *q && ( d || !isspace(*q) ); q++)
79
	    if (*q == '\"') d = d ? 0 : 1;
80
	if (d) {
81
	    strcpy(RunError, "A \" is missing (expandcmd)");
82
	    return NULL;
83
	}
84
	c = *q; /* character after the command, normally a space */
83756 kalibera 85
	*q = '\0'; /* modifies buf */
6153 guido 86
    }
12256 pd 87
 
52804 ripley 88
    /*
89
     * Guido resorted to this since SearchPath returned FOUND also
90
     * for file name without extension -> explicitly set
91
     *  extension
92
     */
93
    for (f = p, ext = 0 ; *f ; f++) {
41793 ripley 94
	if ((*f == '\\') || (*f == '/')) ext = 0;
95
	else if (*f == '.') ext = 1;
96
    }
97
    /* SearchPath doesn't like ", so strip out quotes */
52804 ripley 98
    for (dest = fl , src = p; *src ; src++)
99
	if (*src != '"') *dest++ = *src;
41793 ripley 100
    *dest = '\0';
101
    if (ext) {
102
	/*
103
	 * user set extension; we don't check that it is executable;
104
	 * it might get an error after; but maybe sometimes
105
	 * in the future every extension will be executable
106
	 */
83695 kalibera 107
	d = SearchPath(NULL, fl, NULL, 0, NULL, &f);
41793 ripley 108
    } else {
109
	int iexts = 0;
83756 kalibera 110
	/* update the size of fl above if adding extensions longer than 3 chars */
43800 ripley 111
	const char *exts[] = { ".exe" , ".com" , ".cmd" , ".bat" , NULL };
41793 ripley 112
	while (exts[iexts]) {
83756 kalibera 113
	    strcpy(dest, exts[iexts]); /* modifies fl */
83695 kalibera 114
	    if ((d = SearchPath(NULL, fl, NULL, 0, NULL, &f))) break;
41793 ripley 115
	    iexts++ ;
116
	}
117
    }
83695 kalibera 118
    if (d > 0) {
119
	/* perform the search again with the right buffer size */
83756 kalibera 120
 
121
	/* The +10 below is a hack to work-around what appears to be a bug
84215 maechler 122
	   observed on Windows 10 (build 19045). When the corresponding PATH
83756 kalibera 123
	   entry ends with one or more extra separators (e.g. dir\/,
124
	   dir\\ or dir//), the nBufferLength argument must be increased by
125
	   that number, otherwise SearchPath reports the path doesn't fit.
126
	   When the number is increased, the path is returned correctly
127
	   without the extra separators. */
128
	if (!(fn = (char *) malloc(d + 10))) {
83695 kalibera 129
	    strcpy(RunError, "Insufficient memory (expandcmd)");
130
	    return NULL;
131
	}
83756 kalibera 132
	DWORD oldd = d;
133
	d = SearchPath(NULL, fl, NULL, d + 10, fn, &f);
134
	if (d >= oldd)
135
	    /* treat as error when path doesn't fit now */
136
	    d = 0;
83695 kalibera 137
    }
83756 kalibera 138
    if (!d)    {
83695 kalibera 139
	if (fn) free(fn);
52804 ripley 140
	snprintf(RunError, 500, "'%s' not found", p);
41793 ripley 141
	return NULL;
142
    }
143
    /*
65574 ripley 144
      NB: as of Windows 7 SearchPath does not return short names any more.
145
 
6153 guido 146
      Paranoia : on my system switching to short names is not needed
147
      since SearchPath already returns 'short names'. However,
148
      this is not documented so I prefer to be explicit.
41793 ripley 149
    */
80742 kalibera 150
    /* NOTE: short names are not always enabled/available. In that case,
151
       GetShortPathName may succeed and return the original (long) name. */
83695 kalibera 152
 
153
    res = GetShortPathName(fn, NULL, 0);
154
    if (res > 0) {
83756 kalibera 155
	/* perform the translation again with sufficient buffer size */
83695 kalibera 156
	// This is the return value.
85539 kalibera 157
	if (!(s = (char *) malloc(res + len + 2))) {
158
	    /* the size over-estimate, +2 in case quotes will be needed */
83695 kalibera 159
	    if (fn) free(fn);
160
	    strcpy(RunError, "Insufficient memory (expandcmd)");
161
	    return NULL;
162
	}
163
	res = GetShortPathName(fn, s, res);
164
    }
165
    if (res == 0) {
80742 kalibera 166
	/* Use full name if GetShortPathName fails, i.e. due to insufficient
167
	   permissions for some component of the path. */
83756 kalibera 168
	if (s) free(s);
83695 kalibera 169
	// This is the return value.
85539 kalibera 170
	if (!(s = (char *) malloc(d + len + 2))) { /* over-estimate */
83695 kalibera 171
	    if (fn) free(fn);
172
	    strcpy(RunError, "Insufficient memory (expandcmd)");
173
	    return NULL;
174
	}
85539 kalibera 175
	if (!whole && hasspace(fn)) 
176
	    snprintf(s, d + 3, "\"%s\"", fn);
177
	else
178
	    strncpy(s, fn, d + 1);
179
    } else if (!whole && hasspace(s)) {
180
	/* GetShortPathName succeeded but it may still have returned the
181
	   long path (so with spaces) */
182
 
183
	memmove(s + 1, s, res + 1); 
184
	s[0] = '"';
185
	s[1 + res] = '"';
186
	s[1 + res + 1] = '\0';
83695 kalibera 187
    }
80742 kalibera 188
 
59546 ripley 189
    if (!whole) {
83756 kalibera 190
	*q = c;         /* restore character after command */
191
	strcat(s, q);   /* add the rest of input (usually arguments) */
59546 ripley 192
    }
83695 kalibera 193
    if (fn) free(fn);
41793 ripley 194
    return s;
4394 ripley 195
}
196
 
27774 murdoch 197
/*
12256 pd 198
   finput is either NULL or the name of a file from which to
199
     redirect stdin for the child.
200
   newconsole != 0 to use a new console (if not waiting)
201
   visible = -1, 0, 1 for hide, minimized, default
53870 murdoch 202
   inpipe != 0 to duplicate I/O handles
52813 ripley 203
   pi is set based on the newly created process,
204
   with the hThread handle closed.
12256 pd 205
*/
206
 
44013 ripley 207
extern size_t Rf_utf8towcs(wchar_t *wc, const char *s, size_t n);
208
 
85648 kalibera 209
/* NOTE: this doesn't work for CE_UTF8 due to expandcmd() */
52814 ripley 210
static void pcreate(const char* cmd, cetype_t enc,
211
		      int newconsole, int visible,
51030 murdoch 212
		      HANDLE hIN, HANDLE hOUT, HANDLE hERR,
84676 kalibera 213
		      pinfo *pi, int consignals)
4394 ripley 214
{
215
    DWORD ret;
216
    STARTUPINFO si;
44013 ripley 217
    STARTUPINFOW wsi;
77919 kalibera 218
    HANDLE dupIN, dupOUT, dupERR, job, port = NULL;
51015 murdoch 219
    WORD showWindow = SW_SHOWDEFAULT;
75992 kalibera 220
    DWORD flags;
221
    BOOL inJob;
222
    Rboolean breakaway;
223
    JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli;
224
    JOBOBJECT_ASSOCIATE_COMPLETION_PORT cport;
53870 murdoch 225
    int inpipe;
4394 ripley 226
    char *ecmd;
51015 murdoch 227
    SECURITY_ATTRIBUTES sa;
4394 ripley 228
    sa.nLength = sizeof(sa);
229
    sa.lpSecurityDescriptor = NULL;
230
    sa.bInheritHandle = TRUE;
231
 
85648 kalibera 232
    /* FIXME: this would have to be done in wchar_t/UTF-16LE to support
233
       CE_UTF8; the enc==CE_UTF8 branch could be phased out once UTF-8 as
234
       native encoding can be assumed on all Windows systems  */
59546 ripley 235
    if (!(ecmd = expandcmd(cmd, 0))) return; /* error message already set */
51015 murdoch 236
 
53870 murdoch 237
    inpipe = (hIN != INVALID_HANDLE_VALUE)
238
	|| (hOUT != INVALID_HANDLE_VALUE)
239
	|| (hERR != INVALID_HANDLE_VALUE);
52814 ripley 240
 
53870 murdoch 241
    if (inpipe) {
242
	HANDLE hNULL = CreateFile("NUL:", GENERIC_READ | GENERIC_WRITE, 0,
243
			   &sa, OPEN_EXISTING, 0, NULL);
244
	HANDLE hTHIS = GetCurrentProcess();
51015 murdoch 245
 
53870 murdoch 246
	if (hIN == INVALID_HANDLE_VALUE) hIN = hNULL;
247
	if (hOUT == INVALID_HANDLE_VALUE) hOUT = hNULL;
248
	if (hERR == INVALID_HANDLE_VALUE) hERR = hNULL;
249
 
250
	DuplicateHandle(hTHIS, hIN,
251
			hTHIS, &dupIN, 0, TRUE, DUPLICATE_SAME_ACCESS);
252
	DuplicateHandle(hTHIS, hOUT,
253
			hTHIS, &dupOUT, 0, TRUE, DUPLICATE_SAME_ACCESS);
254
	DuplicateHandle(hTHIS, hERR,
255
			hTHIS, &dupERR, 0, TRUE, DUPLICATE_SAME_ACCESS);
256
	CloseHandle(hTHIS);
257
	CloseHandle(hNULL);
258
    }
259
 
51015 murdoch 260
    switch (visible) {
261
    case -1:
262
	showWindow = SW_HIDE;
263
	break;
264
    case 0:
265
	showWindow = SW_SHOWMINIMIZED;
266
	break;
4394 ripley 267
    }
52814 ripley 268
 
44013 ripley 269
    if(enc == CE_UTF8) {
270
	wsi.cb = sizeof(wsi);
271
	wsi.lpReserved = NULL;
272
	wsi.lpReserved2 = NULL;
273
	wsi.cbReserved2 = 0;
274
	wsi.lpDesktop = NULL;
275
	wsi.lpTitle = NULL;
51015 murdoch 276
	wsi.dwFlags = STARTF_USESHOWWINDOW;
52814 ripley 277
	wsi.wShowWindow = showWindow;
53870 murdoch 278
	if (inpipe) {
279
	    wsi.dwFlags |= STARTF_USESTDHANDLES;
280
	    wsi.hStdInput  = dupIN;
281
	    wsi.hStdOutput = dupOUT;
282
	    wsi.hStdError  = dupERR;
283
	}
44013 ripley 284
    } else {
285
	si.cb = sizeof(si);
286
	si.lpReserved = NULL;
287
	si.lpReserved2 = NULL;
288
	si.cbReserved2 = 0;
289
	si.lpDesktop = NULL;
290
	si.lpTitle = NULL;
51015 murdoch 291
	si.dwFlags = STARTF_USESHOWWINDOW;
52814 ripley 292
	si.wShowWindow = showWindow;
53870 murdoch 293
	if (inpipe) {
294
	    si.dwFlags |= STARTF_USESTDHANDLES;
295
	    si.hStdInput  = dupIN;
296
	    si.hStdOutput = dupOUT;
297
	    si.hStdError  = dupERR;
298
	}
4394 ripley 299
    }
44013 ripley 300
 
75992 kalibera 301
    /* Originally, the external process has been waited for only using
302
       waitForSingleObject, but that has been proven unreliable: sometimes
303
       the output file would still be opened (and hence locked) by some
304
       child process after waitForSingleObject would finish. This has been
305
       observed also while running tests and particularly when building
306
       vignettes, resulting in spurious "Permission denied" errors.
307
 
308
       This has been happening almost surely due to a child process not
309
       waiting for its own children to finish, which has been reported
310
       to happen with Linux utilities ported to Windows as used for tests
311
       in Haskell/GHC. Inspired by Haskell process and a blog post about
312
       waiting for a process tree to finish, we now use job objects to
313
       wait also for process trees with this issue:
314
 
315
	https://github.com/haskell/process
316
	https://blogs.msdn.microsoft.com/oldnewthing/20130405-00/?p=4743
317
 
318
       In addition, we try to be easy on applications coded to rely on that
319
       they do not run in a job, when running in old Windows that do not
82247 kalibera 320
       support nested jobs. On newer versions of Windows, we use nested jobs.
75992 kalibera 321
    */
322
 
323
    /* Creating the process with CREATE_BREAKAWAY_FROM_JOB is safe when
324
       the process is not in any job or when it is in a job that allows it.
325
       The documentation does not say what would happen if we set the flag,
82247 kalibera 326
       but run in a job that does not allow it, so better don't.
327
 
328
       Do not consider breakaway on Windows 8 (Windows Server 2012) and newer,
329
       but instead use nested jobs.
330
    */
75992 kalibera 331
    breakaway = FALSE;
82247 kalibera 332
    if (!IsWindows8OrGreater() &&
333
        IsProcessInJob(GetCurrentProcess(), NULL, &inJob) && inJob) {
75992 kalibera 334
	/* The documentation does not say that it would be ok to use
335
	   QueryInformationJobObject when the process is not in the job,
336
	   so we have better tested that upfront. */
337
	ZeroMemory(&jeli, sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
338
	ret = QueryInformationJobObject(
339
		NULL,
340
	        JobObjectExtendedLimitInformation,
341
	        &jeli,
342
	        sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION),
343
		NULL);
344
	breakaway = ret &&
345
		(jeli.BasicLimitInformation.LimitFlags &
346
	         JOB_OBJECT_LIMIT_BREAKAWAY_OK);
347
    }
348
 
349
    /* create a job that allows breakaway */
350
    job = CreateJobObject(NULL, NULL);
351
    if (job) {
352
	ZeroMemory(&jeli, sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
82247 kalibera 353
	jeli.BasicLimitInformation.LimitFlags =
354
	    /* JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE helps to terminate grand
355
	       child processes when the child process executed is R
356
	       and breakaway is used. */
357
	    JOB_OBJECT_LIMIT_BREAKAWAY_OK | JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
75992 kalibera 358
	ret = SetInformationJobObject(
359
		job,
360
		JobObjectExtendedLimitInformation,
361
		&jeli,
362
                sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
363
	if (!ret) {
364
	    CloseHandle(job);
365
	    job = NULL;
366
	}
367
    }
368
 
369
    /* create a completion port to learn when processes exit */
370
    if (job) {
371
	port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
372
	if (!port) {
373
	    CloseHandle(job);
374
	    job = NULL;
375
	}
376
    }
377
    if (job) {
378
	ZeroMemory(&cport, sizeof(JOBOBJECT_ASSOCIATE_COMPLETION_PORT));
379
	cport.CompletionKey = job; /* use job handle as key */
380
	cport.CompletionPort = port;
381
	ret = SetInformationJobObject(
382
	    job,
383
	    JobObjectAssociateCompletionPortInformation,
384
	    &cport,
385
	    sizeof(JOBOBJECT_ASSOCIATE_COMPLETION_PORT));
386
	if (!ret) {
387
	    CloseHandle(job);
388
	    CloseHandle(port);
389
	    job = NULL;
390
	}
391
    }
392
 
393
    flags = 0;
394
    if (job)
395
	flags |= CREATE_SUSPENDED; /* assign to job before it runs */
396
    if (newconsole && (visible == 1))
397
	flags |= CREATE_NEW_CONSOLE;
84676 kalibera 398
    else if (newconsole && !consignals)
84419 kalibera 399
	/* prevent interruption of background processes by Ctrl-C, PR#17764 */
400
	flags |= CREATE_NEW_PROCESS_GROUP;
75992 kalibera 401
    if (job && breakaway)
402
	flags |= CREATE_BREAKAWAY_FROM_JOB;
403
 
44013 ripley 404
    if(enc == CE_UTF8) {
405
	int n = strlen(ecmd); /* max no of chars */
52804 ripley 406
	wchar_t wcmd[n+1];
44013 ripley 407
	Rf_utf8towcs(wcmd, ecmd, n+1);
75992 kalibera 408
	ret = CreateProcessW(NULL, wcmd, &sa, &sa, TRUE, flags,
409
			     NULL, NULL, &wsi, &(pi->pi));
45070 ripley 410
    } else
75992 kalibera 411
	ret = CreateProcess(NULL, ecmd, &sa, &sa, TRUE, flags,
412
			    NULL, NULL, &si, &(pi->pi));
44013 ripley 413
 
75992 kalibera 414
    if (ret && job) {
415
	/* process was created as suspended */
416
	if (!AssignProcessToJobObject(job, pi->pi.hProcess)) {
417
	    /* will fail running on Windows without support for nested jobs,
418
	       when running in a job that does not allow breakaway */
419
	    CloseHandle(job);
420
	    CloseHandle(port);
421
	    job = NULL;
422
	}
423
	ResumeThread(pi->pi.hThread);
424
    }
425
 
426
    if (ret && job) {
427
	/* process is running in new job */
428
	pi->job = job;
429
	pi->port = port;
430
    } else {
431
	if (job) {
432
	    CloseHandle(job);
433
	    CloseHandle(port);
434
	    job = NULL;
435
	}
436
	pi->job = NULL;
437
	pi->port = NULL;
438
    }
439
 
53870 murdoch 440
    if (inpipe) {
441
	CloseHandle(dupIN);
442
	CloseHandle(dupOUT);
443
	CloseHandle(dupERR);
444
    }
52804 ripley 445
    if (!ret)
60844 ripley 446
	snprintf(RunError, 500, _("'CreateProcess' failed to run '%s'"), ecmd);
75992 kalibera 447
    else CloseHandle(pi->pi.hThread);
11169 ripley 448
    free(ecmd);
51030 murdoch 449
    return;
4394 ripley 450
}
451
 
12256 pd 452
/* used in rpipeOpen */
453
static DWORD CALLBACK
4394 ripley 454
threadedwait(LPVOID param)
455
{
456
    rpipe *p = (rpipe *) param;
457
 
72855 kalibera 458
    if (p->timeoutMillis) {
75992 kalibera 459
	DWORD wres = WaitForSingleObject(p->pi.pi.hProcess, p->timeoutMillis);
72855 kalibera 460
	if (wres == WAIT_TIMEOUT) {
75992 kalibera 461
	    TerminateProcess(p->pi.pi.hProcess, 124);
72855 kalibera 462
	    p->timedout = 1;
463
	    /* wait up to 10s for the  process to actually terminate */
75992 kalibera 464
	    WaitForSingleObject(p->pi.pi.hProcess, 10000);
72855 kalibera 465
	}
466
    } else 
75992 kalibera 467
	WaitForSingleObject(p->pi.pi.hProcess, INFINITE);
72855 kalibera 468
 
469
    DWORD ret;
75992 kalibera 470
    GetExitCodeProcess(p->pi.pi.hProcess, &ret);
72855 kalibera 471
    p->exitcode = ret;
472
 
4394 ripley 473
    FlushFileBuffers(p->write);
474
    FlushFileBuffers(p->read);
475
    p->active = 0;
51030 murdoch 476
    CloseHandle(p->thread);
477
    p->thread = NULL;
4394 ripley 478
    return 0;
479
}
480
 
44201 ripley 481
char *runerror(void)
4394 ripley 482
{
483
    return RunError;
484
}
485
 
52814 ripley 486
static HANDLE getInputHandle(const char *fin)
51015 murdoch 487
{
52814 ripley 488
    if (fin && fin[0]) {
51015 murdoch 489
	SECURITY_ATTRIBUTES sa;
490
	sa.nLength = sizeof(sa);
491
	sa.lpSecurityDescriptor = NULL;
52814 ripley 492
	sa.bInheritHandle = TRUE;
493
	HANDLE hIN = CreateFile(fin, GENERIC_READ, 0,
494
				&sa, OPEN_EXISTING, 0, NULL);
51015 murdoch 495
	if (hIN == INVALID_HANDLE_VALUE) {
52814 ripley 496
	    snprintf(RunError, 500, 
497
		     "unable to redirect input from '%s'", fin);
51015 murdoch 498
	    return NULL;
499
	}
500
	return hIN;
55955 murdoch 501
    } else if (fin) {
502
        /* GetStdHandle returns NULL for processes like RGui with no standard handles defined */
503
    	HANDLE result = GetStdHandle(STD_INPUT_HANDLE);
504
    	if (result) return result;
505
    }
51015 murdoch 506
    return INVALID_HANDLE_VALUE;
507
}
4394 ripley 508
 
53348 ripley 509
static HANDLE getOutputHandle(const char *fout, int type)
52814 ripley 510
{
511
    if (fout && fout[0]) {
512
	SECURITY_ATTRIBUTES sa;
513
	sa.nLength = sizeof(sa);
514
	sa.lpSecurityDescriptor = NULL;
515
	sa.bInheritHandle = TRUE;
516
	HANDLE hOUT = CreateFile(fout, GENERIC_WRITE, 0,
517
				 &sa, CREATE_ALWAYS, 0, NULL);
518
	if (hOUT == INVALID_HANDLE_VALUE) {
519
	    snprintf(RunError, 500, 
520
		     "unable to redirect output to '%s'", fout);
521
	    return NULL;
52836 ripley 522
	} else return hOUT;
55955 murdoch 523
    } else if (fout) {
524
        /* GetStdHandle returns NULL for processes like RGui */
525
        HANDLE result = GetStdHandle(type ? STD_ERROR_HANDLE : STD_OUTPUT_HANDLE);
526
        if (result) return result;
527
    }
52814 ripley 528
    return INVALID_HANDLE_VALUE;
529
}
530
 
51030 murdoch 531
BOOL CALLBACK TerminateWindow(HWND hwnd, LPARAM lParam)
532
{
533
    DWORD ID ;
534
 
535
    GetWindowThreadProcessId(hwnd, &ID);
536
 
537
    if (ID == (DWORD)lParam)
52814 ripley 538
	PostMessage(hwnd, WM_CLOSE, 0, 0);
51030 murdoch 539
    return TRUE;
540
}
541
 
542
/* Terminate the process pwait2 is waiting for. */
543
 
544
extern void GA_askok(const char *info);
545
 
75992 kalibera 546
static void waitForJob(pinfo *pi, DWORD timeoutMillis, int* timedout)
547
{
548
    DWORD code, ret;
549
    ULONG_PTR key;
550
    DWORD beforeMillis;
551
    JOBOBJECT_BASIC_ACCOUNTING_INFORMATION jbai;
552
    LPOVERLAPPED overlapped; /* not used */
553
    DWORD queryMillis;
554
 
555
    if (timeoutMillis)
556
	beforeMillis = timeGetTime();
557
 
558
    queryMillis = 0;
559
    for(;;) {
560
	ret = GetQueuedCompletionStatus(pi->port, &code, &key,
561
					&overlapped, queryMillis);
562
	if (ret && code == JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO &&
563
	    (HANDLE)key == pi->job)
564
	    break;
565
 
566
	/* start with short query timeouts because notifications often get lost,
567
	   this is essentially polling */
568
 
569
	if (queryMillis == 0)
570
	    queryMillis = 1;
571
	else if (queryMillis < 100)
572
	    queryMillis *= 2;
573
 
574
	if (timeoutMillis && (timeGetTime() - beforeMillis >= timeoutMillis)) {
575
	    if (timedout)
576
		*timedout = 1;
577
	    break;
578
	}
579
 
580
	/* Check also explicitly because notifications are documented to get
581
	   lost and they often do. */
582
	ZeroMemory(&jbai, sizeof(JOBOBJECT_BASIC_ACCOUNTING_INFORMATION));
583
	ret = QueryInformationJobObject(
584
		pi->job,
585
		JobObjectBasicAccountingInformation,
586
		&jbai,
587
		sizeof(JOBOBJECT_BASIC_ACCOUNTING_INFORMATION),
588
		NULL);
589
	if (ret && jbai.ActiveProcesses == 0)
590
	    break;
591
    }
592
    CloseHandle(pi->port);
593
    CloseHandle(pi->job);
594
}
595
 
51030 murdoch 596
static void terminate_process(void *p)
597
{
75992 kalibera 598
    pinfo *pi = (pinfo*) p;
599
    EnumWindows((WNDENUMPROC)TerminateWindow, (LPARAM)pi->pi.dwProcessId);
52814 ripley 600
 
75992 kalibera 601
    if (WaitForSingleObject(pi->pi.hProcess, 5000) == WAIT_TIMEOUT) {
52814 ripley 602
	if (R_Interactive)
603
	    GA_askok(_("Child process not responding.  R will terminate it."));
75992 kalibera 604
	TerminateProcess(pi->pi.hProcess, 99);
51030 murdoch 605
    }
75992 kalibera 606
 
82247 kalibera 607
    if (pi->job) {
608
	TerminateJobObject(pi->job, 99);
75992 kalibera 609
	waitForJob(pi, 2000, NULL);
82247 kalibera 610
    }
51030 murdoch 611
}
612
 
75992 kalibera 613
static int pwait2(pinfo *pi, DWORD timeoutMillis, int* timedout)
51030 murdoch 614
{
615
    DWORD ret;
616
 
72855 kalibera 617
    if (!timeoutMillis) {
75992 kalibera 618
	while( WaitForSingleObject(pi->pi.hProcess, 100) == WAIT_TIMEOUT )
72855 kalibera 619
	    R_CheckUserInterrupt();
620
    } else {
621
	DWORD beforeMillis = timeGetTime();
75992 kalibera 622
	while( WaitForSingleObject(pi->pi.hProcess, 100) == WAIT_TIMEOUT ) {
72855 kalibera 623
	    R_CheckUserInterrupt();
624
	    DWORD afterMillis = timeGetTime();
625
	    if (afterMillis - beforeMillis >= timeoutMillis) {
75992 kalibera 626
		TerminateProcess(pi->pi.hProcess, 124);
72855 kalibera 627
		if (timedout)
628
		    *timedout = 1;
629
		/* wait up to 10s for the process to actually terminate */
75992 kalibera 630
		WaitForSingleObject(pi->pi.hProcess, 10000);
82247 kalibera 631
		if (pi->job)
632
		    TerminateJobObject(pi->job, 124);
72855 kalibera 633
		break;
634
	    }
635
	}
636
    }
52814 ripley 637
 
75992 kalibera 638
    GetExitCodeProcess(pi->pi.hProcess, &ret);
639
 
640
    if (pi->job)
641
	waitForJob(pi, timeoutMillis, timedout);
642
 
51030 murdoch 643
    return ret;
644
}
645
 
12256 pd 646
/*
52813 ripley 647
  Used for external commands in file.show() and edit(), and for
52814 ripley 648
  system(intern=FALSE).  Also called from postscript().
52813 ripley 649
 
650
  wait != 0 says wait for child to terminate before returning.
651
  visible = -1, 0, 1 for hide, minimized, default
52814 ripley 652
  fin is either NULL or the name of a file from which to
52813 ripley 653
  redirect stdin for the child.
53348 ripley 654
  fout/ferr are NULL (use NUL:), "" (use standard streams) or filenames.
52813 ripley 655
*/
52814 ripley 656
int runcmd(const char *cmd, cetype_t enc, int wait, int visible,
657
	   const char *fin, const char *fout, const char *ferr)
4394 ripley 658
{
84676 kalibera 659
    return runcmd_timeout(cmd, enc, wait, visible, fin, fout, ferr, 0, NULL, 1);
72855 kalibera 660
}
661
 
662
int runcmd_timeout(const char *cmd, cetype_t enc, int wait, int visible,
663
                   const char *fin, const char *fout, const char *ferr,
84676 kalibera 664
                   int timeout, int *timedout, int consignals)
72855 kalibera 665
{
666
    if (!wait && timeout)
667
	error("Timeout with background running processes is not supported.");
668
 
52837 ripley 669
    HANDLE hIN = getInputHandle(fin), hOUT, hERR;
51030 murdoch 670
    int ret = 0;
75992 kalibera 671
    pinfo pi;
53870 murdoch 672
    int close1 = 0, close2 = 0, close3 = 0;
673
 
674
    if (hIN && fin && fin[0]) close1 = 1;
12256 pd 675
 
53348 ripley 676
    hOUT = getOutputHandle(fout, 0);
677
    if (!hOUT) return 1;
53572 ripley 678
    if (fout && fout[0]) close2 = 1;
53348 ripley 679
    if (fout && fout[0] && ferr && streql(fout, ferr)) hERR = hOUT;
680
    else { 
681
	hERR = getOutputHandle(ferr, 1);
682
	if (!hERR) return 1;
683
	if (ferr && ferr[0]) close3 = 1;
684
    }
52836 ripley 685
 
53348 ripley 686
 
75992 kalibera 687
    memset(&(pi.pi), 0, sizeof(PROCESS_INFORMATION));
84676 kalibera 688
    pcreate(cmd, enc, !wait, visible, hIN, hOUT, hERR, &pi, consignals);
75992 kalibera 689
    if (pi.pi.hProcess) {
64237 murdoch 690
	if (wait) {
691
	    RCNTXT cntxt;
692
	    begincontext(&cntxt, CTXT_CCODE, R_NilValue, R_BaseEnv, R_BaseEnv,
693
		     R_NilValue, R_NilValue);
694
	    cntxt.cend = &terminate_process;
695
	    cntxt.cenddata = &pi;
72855 kalibera 696
	    DWORD timeoutMillis = (DWORD) (1000*timeout);
75992 kalibera 697
	    ret = pwait2(&pi, timeoutMillis, timedout);
64237 murdoch 698
	    endcontext(&cntxt);
699
	    snprintf(RunError, 501, _("Exit code was %d"), ret);
700
	    ret &= 0xffff;
701
	} else ret = 0;
75992 kalibera 702
	CloseHandle(pi.pi.hProcess);
64237 murdoch 703
    } else {
704
    	ret = NOLAUNCH;
705
    }
53870 murdoch 706
    if (close1) CloseHandle(hIN);
53348 ripley 707
    if (close2) CloseHandle(hOUT);
708
    if (close3) CloseHandle(hERR);
4394 ripley 709
    return ret;
710
}
711
 
12256 pd 712
/*
713
   finput is either NULL or the name of a file from which to
714
     redirect stdin for the child.
715
   visible = -1, 0, 1 for hide, minimized, default
40468 ripley 716
   io = 0 to read stdout from pipe, 1 to write to pipe,
52814 ripley 717
   2 to read stderr from pipe, 
718
   3 to read both stdout and stderr from pipe.
12256 pd 719
 */
45070 ripley 720
rpipe * rpipeOpen(const char *cmd, cetype_t enc, int visible,
53572 ripley 721
		  const char *finput, int io,
72855 kalibera 722
		  const char *fout, const char *ferr,
84419 kalibera 723
		  int timeout, int newconsole)
4394 ripley 724
{
725
    rpipe *r;
53572 ripley 726
    HANDLE hTHIS, hIN, hOUT, hERR, hReadPipe, hWritePipe;
4394 ripley 727
    DWORD id;
12256 pd 728
    BOOL res;
53870 murdoch 729
    int close1 = 0, close2 = 0, close3 = 0;
84676 kalibera 730
    /* newconsole (~"!wait") means ignore Ctrl handler attribute
84419 kalibera 731
       is set for child. When also visible==1, an actual text
84676 kalibera 732
       console is created. */
4394 ripley 733
 
11169 ripley 734
    if (!(r = (rpipe *) malloc(sizeof(struct structRPIPE)))) {
32888 ripley 735
	strcpy(RunError, _("Insufficient memory (rpipeOpen)"));
4394 ripley 736
	return NULL;
737
    }
51030 murdoch 738
    r->active = 0;
75992 kalibera 739
    r->pi.pi.hProcess = NULL;
740
    r->pi.job = NULL;
51030 murdoch 741
    r->thread = NULL;
72855 kalibera 742
    r->timedout = 0;
743
    r->timeoutMillis = (DWORD) (1000*timeout);
51015 murdoch 744
    res = CreatePipe(&hReadPipe, &hWritePipe, NULL, 0);
745
    if (res == FALSE) {
72855 kalibera 746
	rpipeClose(r, NULL);
52804 ripley 747
	strcpy(RunError, "CreatePipe failed");
51015 murdoch 748
	return NULL;
749
    }
84419 kalibera 750
    hTHIS = GetCurrentProcess();
751
    if (io == 1) { /* pipe for R to write to */
51015 murdoch 752
	r->read = hReadPipe;
753
	DuplicateHandle(hTHIS, hWritePipe, hTHIS, &r->write,
12256 pd 754
			0, FALSE, DUPLICATE_SAME_ACCESS);
51015 murdoch 755
	CloseHandle(hWritePipe);
84419 kalibera 756
    } else { /* pipe for R to read from */
757
	r->write = hWritePipe;
758
	DuplicateHandle(hTHIS, hReadPipe, hTHIS, &r->read,
759
			0, FALSE, DUPLICATE_SAME_ACCESS);
760
	CloseHandle(hReadPipe);
12256 pd 761
    }
4394 ripley 762
    CloseHandle(hTHIS);
52814 ripley 763
 
84419 kalibera 764
    if (io == 1)
765
	hIN = r->read;
766
    else {
767
	hIN = getInputHandle(finput); /* a file or (usually NUL:) */
768
	if (hIN && finput && finput[0]) close1 = 1;
769
    }    
770
    if (io == 0 || io == 3) 
53572 ripley 771
	hOUT = r->write;
772
    else {
773
 	hOUT = getOutputHandle(fout, 0);
84419 kalibera 774
	if (hOUT && fout && fout[0]) close2 = 1;
53572 ripley 775
    }
776
    if (io >= 2) 
777
	hERR = r->write;
778
    else {
779
	hERR = getOutputHandle(ferr, 1);
84419 kalibera 780
	if (hERR && ferr && ferr[0]) close3 = 1;
53572 ripley 781
    }
84419 kalibera 782
 
84676 kalibera 783
    pcreate(cmd, enc, newconsole, visible, hIN, hOUT, hERR, &(r->pi), 0);
84419 kalibera 784
 
53870 murdoch 785
    if (close1) CloseHandle(hIN);
53572 ripley 786
    if (close2) CloseHandle(hOUT);
787
    if (close3) CloseHandle(hERR);
52814 ripley 788
 
4394 ripley 789
    r->active = 1;
75992 kalibera 790
    if (!r->pi.pi.hProcess)
4394 ripley 791
	return NULL;
84419 kalibera 792
    if (io != 1) {
793
	/* FIXME: if still needed, should it be used also for io == 1? */
794
	if (!(r->thread = CreateThread(NULL, 0, threadedwait, r, 0, &id))) {
795
	    rpipeClose(r, NULL);
796
	    strcpy(RunError, "CreateThread failed");
797
	    return NULL;
798
	}
4394 ripley 799
    }
800
    return r;
801
}
802
 
52814 ripley 803
static void
51030 murdoch 804
rpipeTerminate(rpipe * r)
805
{
806
    if (r->thread) {
52814 ripley 807
	TerminateThread(r->thread, 0);
808
	CloseHandle(r->thread);
809
	r->thread = NULL;
51030 murdoch 810
    }
811
    if (r->active) {
52814 ripley 812
	terminate_process(&(r->pi));
813
	r->active = 0;
51030 murdoch 814
    }
815
}
816
 
40513 ripley 817
#include "graphapp/ga.h"
818
extern Rboolean UserBreak;
4394 ripley 819
 
12256 pd 820
int
4394 ripley 821
rpipeGetc(rpipe * r)
822
{
823
    DWORD a, b;
824
    char  c;
825
 
826
    if (!r)
827
	return NOLAUNCH;
828
    while (PeekNamedPipe(r->read, NULL, 0, NULL, &a, NULL)) {
829
	if (!a && !r->active) {
830
	    /* I got a case in which process terminated after Peek.. */
831
	    PeekNamedPipe(r->read, NULL, 0, NULL, &a, NULL);
12256 pd 832
	    if (!a) return NOLAUNCH;/* end of pipe */
4394 ripley 833
	}
834
	if (a) {
835
	    if (ReadFile(r->read, &c, 1, &b, NULL) == TRUE)
836
		return c;
837
	    else
838
		return NOLAUNCH;/* error but...treated as eof */
839
	}
40513 ripley 840
	/* we want to look for user break here */
841
	while (peekevent()) doevent();
842
	if (UserBreak) {
79250 kalibera 843
	    /* FIXME: close handles */
51030 murdoch 844
	    rpipeTerminate(r);
40513 ripley 845
	    break;
846
	}
847
	R_ProcessEvents();
848
	Sleep(100);
4394 ripley 849
    }
850
    return NOLAUNCH;		/* again.. */
851
}
852
 
853
 
12256 pd 854
char * rpipeGets(rpipe * r, char *buf, int len)
4394 ripley 855
{
856
    int   i, c;
857
 
12256 pd 858
    if ((len < 2) || !r) return NULL;
4394 ripley 859
    for (i = 0; i < (len - 1); i++) {
860
	if ((c = rpipeGetc(r)) == NOLAUNCH) {
12256 pd 861
	    if (i == 0) return NULL;
4394 ripley 862
	    else {
863
		buf[i] = '\0';
864
		return buf;
865
	    }
866
	}
867
	buf[i] = c;
868
	if (c == '\n') {
869
	    if ((i > 0) && (buf[i - 1] == '\r')) {
870
		buf[i - 1] = '\n';
871
		buf[i] = '\0';
872
	    } else
873
		buf[i + 1] = '\0';
874
	    return buf;
875
	}
876
    }
877
    buf[len - 1] = '\0';
878
    return buf;
879
}
880
 
72855 kalibera 881
int rpipeClose(rpipe *r, int *timedout)
4394 ripley 882
{
883
    int   i;
884
 
12256 pd 885
    if (!r) return NOLAUNCH;
79250 kalibera 886
    /* Close both pipe ends before forcibly terminating the child process to
887
       let it read all data (if it is reading) and exit gracefully.
888
 
889
       r->write and r->read are set to hNULL for the case that threadedwait
890
       ends up flushing file buffers
891
 
892
       FIXME: should we be forcing the termination at all? */
893
    HANDLE hNULL = CreateFile("NUL:", GENERIC_READ | GENERIC_WRITE, 0,
894
                              NULL, OPEN_EXISTING, 0, NULL);
895
    HANDLE tmp;
896
    tmp = r->read;
897
    r->read = hNULL;
898
    CloseHandle(tmp);
899
    tmp = r->write;
900
    r->write = hNULL;
901
    CloseHandle(tmp);
902
 
51030 murdoch 903
    rpipeTerminate(r);
73675 kalibera 904
    /* threadedwait may have obtained the exit code of the pipe process,
905
       but also may have been terminated too early; retrieve the exit
906
       code again to avoid race condition */
907
    DWORD ret;
75992 kalibera 908
    GetExitCodeProcess(r->pi.pi.hProcess, &ret);
73675 kalibera 909
    r->exitcode = ret;
75992 kalibera 910
    CloseHandle(r->pi.pi.hProcess);
79250 kalibera 911
    CloseHandle(hNULL);
4394 ripley 912
    i = r->exitcode;
72855 kalibera 913
    if (timedout)
914
	*timedout = r->timedout;
11169 ripley 915
    free(r);
42618 ripley 916
    return i &= 0xffff;
4394 ripley 917
}
6153 guido 918
 
12256 pd 919
/* ------------------- Windows pipe connections --------------------- */
6153 guido 920
 
12256 pd 921
#include <Fileio.h>
922
#include <Rconnections.h>
6153 guido 923
 
12256 pd 924
typedef struct Wpipeconn {
925
    rpipe *rp;
926
} *RWpipeconn;
6153 guido 927
 
928
 
18611 ripley 929
static Rboolean Wpipe_open(Rconnection con)
12256 pd 930
{
931
    rpipe *rp;
84419 kalibera 932
    int visible = -1, io, mlen, newconsole;
933
    const char *fin = NULL, *fout = NULL, *ferr = NULL;
6153 guido 934
 
84419 kalibera 935
    io = con->mode[0] == 'w'; /* 1 for write, 0 for read */
936
    if (CharacterMode == RTerm) {
937
	fin = fout = ferr = "";
938
	newconsole = 1; /* ensures the child process runs in a new
939
	                   process group (ignores Ctrl handler),
940
	                   PR#17764 */
941
    } else if(io) {
942
	/* FIXME: this opens the extra console in Rgui, but it does not
943
	   get the output */
944
	visible = 1; /* Somewhere to put the output */
945
	newconsole = 1;
946
    } else
947
	newconsole = 0;
948
    rp = rpipeOpen(con->description, con->enc, visible, fin, io, fout, ferr, 0,
949
                   newconsole);
18611 ripley 950
    if(!rp) {
951
	warning("cannot open cmd `%s'", con->description);
952
	return FALSE;
953
    }
12256 pd 954
    ((RWpipeconn)(con->private))->rp = rp;
955
    con->isopen = TRUE;
956
    con->canwrite = io;
957
    con->canread = !con->canwrite;
78045 kalibera 958
    mlen = (int) strlen(con->mode);
959
    if(mlen >= 2 && con->mode[mlen-1] == 'b') con->text = FALSE;
12256 pd 960
    else con->text = TRUE;
961
    con->save = -1000;
18611 ripley 962
    return TRUE;
12256 pd 963
}
6153 guido 964
 
12256 pd 965
static void Wpipe_close(Rconnection con)
966
{
72855 kalibera 967
    con->status = rpipeClose( ((RWpipeconn)con->private) ->rp, NULL);
12256 pd 968
    con->isopen = FALSE;
969
}
970
 
971
static void Wpipe_destroy(Rconnection con)
972
{
973
    free(con->private);
974
}
975
 
976
 
977
static int Wpipe_fgetc(Rconnection con)
978
{
979
    rpipe *rp = ((RWpipeconn)con->private) ->rp;
980
    int c;
27774 murdoch 981
 
13371 ripley 982
    c = rpipeGetc(rp);
12256 pd 983
    return c == NOLAUNCH ? R_EOF : c;
984
}
985
 
986
 
31166 ripley 987
static double null_seek(Rconnection con, double where, int origin, int rw)
12256 pd 988
{
32888 ripley 989
    error(_("seek not enabled for this connection"));
12256 pd 990
    return 0; /* -Wall */
991
}
992
 
13315 ripley 993
static void null_truncate(Rconnection con)
994
{
32888 ripley 995
    error(_("truncate not enabled for this connection"));
13315 ripley 996
}
997
 
12256 pd 998
static int Wpipe_fflush(Rconnection con)
999
{
1000
    BOOL res;
1001
 
1002
    rpipe *rp = ((RWpipeconn)con->private) ->rp;
1003
    res = FlushFileBuffers(rp->write);
1004
    return res ? 0 : EOF;
1005
}
1006
 
1007
static size_t Wpipe_read(void *ptr, size_t size, size_t nitems,
1008
			Rconnection con)
1009
{
1010
    rpipe *rp = ((RWpipeconn)con->private) ->rp;
1011
    DWORD ntoread, read;
1012
 
1013
    while (PeekNamedPipe(rp->read, NULL, 0, NULL, &ntoread, NULL)) {
1014
	if (!ntoread && !rp->active) {
1015
	    /* I got a case in which process terminated after Peek.. */
1016
	    PeekNamedPipe(rp->read, NULL, 0, NULL, &ntoread, NULL);
1017
	    if (!ntoread) return 0; /* end of pipe */
1018
	}
1019
	if (ntoread) {
1020
	    if (ReadFile(rp->read, ptr, nitems * size, &read, NULL) == TRUE)
1021
		return read/size;
1022
	    else return 0; /* error */
1023
	}
1024
    }
1025
    return 0;
1026
}
1027
 
1028
static size_t Wpipe_write(const void *ptr, size_t size, size_t nitems,
1029
			 Rconnection con)
1030
{
1031
    rpipe *rp = ((RWpipeconn)con->private) ->rp;
1032
    DWORD towrite = nitems * size, write, ret;
1033
 
1034
    if(!rp->active) return 0;
75992 kalibera 1035
    GetExitCodeProcess(rp->pi.pi.hProcess, &ret);
12256 pd 1036
    if(ret != STILL_ACTIVE) {
1037
	rp->active = 0;
1038
	warning("broken Windows pipe");
1039
	return 0;
1040
    }
1041
    if (WriteFile(rp->write, ptr, towrite, &write, NULL) != 0)
1042
	return write/size;
1043
    else return 0;
1044
}
1045
 
63220 ripley 1046
#define BUFSIZE 10000
12256 pd 1047
static int Wpipe_vfprintf(Rconnection con, const char *format, va_list ap)
1048
{
63221 ripley 1049
    R_CheckStack2(BUFSIZE);
63181 ripley 1050
    char buf[BUFSIZE], *b = buf;
63220 ripley 1051
    int res = 0;
12256 pd 1052
 
79248 kalibera 1053
    res = Rvsnprintf_mbcs(b, BUFSIZE, format, ap);
1054
    if(res < 0 || res >= BUFSIZE) {
1055
	warning(_("printing of extremely long output is truncated"));
1056
	res = strlen(b);
12256 pd 1057
    }
79248 kalibera 1058
    return Wpipe_write(buf, (size_t)1, (size_t)res, con);
12256 pd 1059
}
1060
 
63219 ripley 1061
 
44013 ripley 1062
Rconnection newWpipe(const char *description, int ienc, const char *mode)
12256 pd 1063
{
1064
    Rconnection new;
42638 murdoch 1065
    char *command;
1066
    int len;
45070 ripley 1067
 
12256 pd 1068
    new = (Rconnection) malloc(sizeof(struct Rconn));
32888 ripley 1069
    if(!new) error(_("allocation of pipe connection failed"));
12256 pd 1070
    new->class = (char *) malloc(strlen("pipe") + 1);
1071
    if(!new->class) {
1072
	free(new);
32888 ripley 1073
	error(_("allocation of pipe connection failed"));
12256 pd 1074
    }
1075
    strcpy(new->class, "pipe");
45070 ripley 1076
 
42638 murdoch 1077
    len = strlen(getenv("COMSPEC")) + strlen(description) + 5;
1078
    command = (char *) malloc(len);
45070 ripley 1079
    if (command)
1080
	new->description = (char *) malloc(len);
42638 murdoch 1081
    else
45070 ripley 1082
	new->description = NULL;
1083
 
12256 pd 1084
    if(!new->description) {
45070 ripley 1085
	free(command); free(new->class); free(new);
32888 ripley 1086
	error(_("allocation of pipe connection failed"));
12256 pd 1087
    }
45070 ripley 1088
 
1089
    /* We always use COMSPEC here, not R_SHELL or SHELL,
1090
       for compatibility with Rterm.
1091
       We also use /c for the same reason.
1092
    */
1093
 
42638 murdoch 1094
    strcpy(command, getenv("COMSPEC"));
1095
    strcat(command, " /c ");
1096
    strcat(command, description);
45070 ripley 1097
 
44013 ripley 1098
    init_con(new, command, ienc, mode);
42638 murdoch 1099
    free(command);
45070 ripley 1100
 
12256 pd 1101
    new->open = &Wpipe_open;
1102
    new->close = &Wpipe_close;
1103
    new->destroy = &Wpipe_destroy;
1104
    new->vfprintf = &Wpipe_vfprintf;
1105
    new->fgetc = &Wpipe_fgetc;
1106
    new->seek = &null_seek;
13315 ripley 1107
    new->truncate = &null_truncate;
12256 pd 1108
    new->fflush = &Wpipe_fflush;
1109
    new->read = &Wpipe_read;
1110
    new->write = &Wpipe_write;
1111
    new->private = (void *) malloc(sizeof(struct Wpipeconn));
1112
    if(!new->private) {
1113
	free(new->description); free(new->class); free(new);
32888 ripley 1114
	error(_("allocation of pipe connection failed"));
12256 pd 1115
    }
1116
    return new;
1117
}
42480 ripley 1118
 
1119
 
1120
SEXP do_syswhich(SEXP call, SEXP op, SEXP args, SEXP env)
1121
{
1122
    SEXP nm, ans;
1123
    int i, n;
82340 kalibera 1124
    const void *vmax = NULL;
42480 ripley 1125
 
82340 kalibera 1126
    vmax = vmaxget();
42480 ripley 1127
    checkArity(op, args);
1128
    nm = CAR(args);
1129
    if(!isString(nm))
61427 ripley 1130
	error(_("'names' is not a character vector"));
42480 ripley 1131
    n = LENGTH(nm);
1132
    PROTECT(ans = allocVector(STRSXP, n));
1133
    for(i = 0; i < n; i++) {
61427 ripley 1134
	if (STRING_ELT(nm, i) == NA_STRING) {
1135
	    SET_STRING_ELT(ans, i, NA_STRING);
1136
	} else {
82340 kalibera 1137
	    const char *this = translateChar(STRING_ELT(nm, i));
61427 ripley 1138
	    char *that = expandcmd(this, 1);
1139
	    SET_STRING_ELT(ans, i, mkChar(that ? that : ""));
1140
	    free(that);
1141
	}
42480 ripley 1142
    }
1143
    setAttrib(ans, R_NamesSymbol, nm);
82340 kalibera 1144
    vmaxset(vmax);
42480 ripley 1145
    UNPROTECT(1);
1146
    return ans;
1147
}