The R Project SVN R

Rev

Rev 77228 | Rev 77769 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
9469 ripley 1
/*
2
 *  R : A Computer Language for Statistical Data Analysis
3
 *  Copyright (C) 1995, 1996  Robert Gentleman and Ross Ihaka
76905 kalibera 4
 *  Copyright (C) 1997--2019  The R Core Team
9469 ripley 5
 *
6
 *  This program is free software; you can redistribute it and/or modify
7
 *  it under the terms of the GNU General Public License as published by
8
 *  the Free Software Foundation; either version 2 of the License, or
9
 *  (at your option) any later version.
10
 *
11
 *  This program is distributed in the hope that it will be useful,
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 *  GNU General Public License for more details.
15
 *
16
 *  You should have received a copy of the GNU General Public License
42300 ripley 17
 *  along with this program; if not, a copy is available at
68956 ripley 18
 *  https://www.R-project.org/Licenses/
9469 ripley 19
 */
20
 
19066 hornik 21
/* See ../unix/system.txt for a description of functions */
9469 ripley 22
 
23
#ifdef HAVE_CONFIG_H
19066 hornik 24
# include <config.h>
9469 ripley 25
#endif
26
 
57540 ripley 27
#define R_USE_SIGNALS 1
9469 ripley 28
#include "Defn.h"
32670 ripley 29
#include <R_ext/Riconv.h>
9469 ripley 30
#include "Fileio.h"
31
#include "graphapp/ga.h"
32
#include "console.h"
33
#include "rui.h"
28991 murdoch 34
#include "editor.h"
9469 ripley 35
#include "getline/getline.h"
43882 ripley 36
#include "getline/wc_history.h"
36901 ripley 37
#define WIN32_LEAN_AND_MEAN 1
58001 ripley 38
/* Mingw-w64 defines this to be 0x0502 */
39
#ifndef _WIN32_WINNT
43328 ripley 40
#define _WIN32_WINNT 0x0500     /* for MEMORYSTATUSEX */
43431 ripley 41
#endif
19066 hornik 42
#include <windows.h>		/* for CreateEvent,.. */
73683 kalibera 43
#include <shlobj.h>		/* for SHGetFolderPath */
19066 hornik 44
#include <process.h>		/* for _beginthread,... */
19096 ripley 45
#include <io.h>			/* for isatty, chdir */
47490 ripley 46
#ifdef _MSC_VER  /* for chdir */
47
# include <direct.h>
48
#endif
9469 ripley 49
#include "run.h"
50
#include "Startup.h"
19761 ripley 51
#include <stdlib.h>		/* for exit */
33088 ripley 52
 
43847 ripley 53
#include "win-nls.h"
33088 ripley 54
 
55668 ripley 55
void R_CleanTempDir(void);		/* from platform.c */
44201 ripley 56
void editorcleanall(void);                  /* from editor.c */
9469 ripley 57
 
32261 ripley 58
int Rwin_graphicsx = -25, Rwin_graphicsy = 0;
20669 ripley 59
 
75450 kalibera 60
R_size_t R_max_memory = R_SIZE_T_MAX;
11007 ripley 61
 
29749 ripley 62
extern SA_TYPE SaveAction; /* from ../main/startup.c */
31698 ripley 63
Rboolean DebugMenuitem = FALSE;  /* exported for rui.c */
40340 ripley 64
static FILE *ifp = NULL;
46078 ripley 65
static char ifile[MAX_PATH] = "\0";
9469 ripley 66
 
47490 ripley 67
__declspec(dllexport) UImode  CharacterMode = RGui; /* some compilers want initialized for export */
9469 ripley 68
int ConsoleAcceptCmd;
43767 ripley 69
void set_workspace_name(const char *fn); /* ../main/startup.c */
9469 ripley 70
 
71
/* used to avoid some flashing during cleaning up */
11067 maechler 72
Rboolean AllDevicesKilled = FALSE;
43767 ripley 73
static int (*R_YesNoCancel)(const char *s);
9469 ripley 74
 
75
static DWORD mainThreadId;
76
 
12976 pd 77
static char oldtitle[512];
9469 ripley 78
 
15716 ripley 79
__declspec(dllexport) Rboolean UserBreak = FALSE;
9469 ripley 80
 
81
/* callbacks */
44201 ripley 82
static void (*R_CallBackHook) (void);
83
static void R_DoNothing(void) {}
9469 ripley 84
static void (*my_R_Busy)(int);
85
 
86
/*
87
 *   Called at I/O, during eval etc to process GUI events.
88
 */
89
 
45188 ripley 90
typedef void (*DO_FUNC)();
45116 ripley 91
static void (* R_Tcl_do)(void) = NULL; /* Initialized to be sure */
45188 ripley 92
 
93
void set_R_Tcldo(DO_FUNC ptr)
45116 ripley 94
{
95
    if (R_Tcl_do)
96
	error("Thief about! Something other than package tcltk has set or is attempting to set R_Tcl_do");
97
    R_Tcl_do = ptr;
98
    return;
99
}
9469 ripley 100
 
45188 ripley 101
void unset_R_Tcldo(DO_FUNC ptr)
45116 ripley 102
{
103
    /* This needs to be a warning not an error, or tcltk will not be able
104
       to be detached. */
105
    if (R_Tcl_do != ptr)
106
	warning("Thief about! Something other than package tcltk has set or is attempting to unset R_Tcl_do");
107
    R_Tcl_do = NULL;
108
    return;
109
}
110
 
9469 ripley 111
void R_ProcessEvents(void)
112
{
113
    while (peekevent()) doevent();
45074 ripley 114
    if (cpuLimit > 0.0 || elapsedLimit > 0.0) {
115
	double cpu, data[5];
116
	R_getProcTime(data);
117
	cpu = data[0] + data[1];  /* children? */
118
	if (elapsedLimit > 0.0 && data[2] > elapsedLimit) {
119
	    cpuLimit = elapsedLimit = -1;
120
	    if (elapsedLimit2 > 0.0 && data[2] > elapsedLimit2) {
121
		elapsedLimit2 = -1.0;
122
		error(_("reached session elapsed time limit"));
123
	    } else
124
		error(_("reached elapsed time limit"));
125
	}
126
	if (cpuLimit > 0.0 && cpu > cpuLimit) {
127
	    cpuLimit = elapsedLimit = -1;
128
	    if (cpuLimit2 > 0.0 && cpu > cpuLimit2) {
129
		cpuLimit2 = -1.0;
130
		error(_("reached session CPU time limit"));
131
	    } else
132
		error(_("reached CPU time limit"));
133
	}
134
    }
9469 ripley 135
    if (UserBreak) {
11067 maechler 136
	UserBreak = FALSE;
25197 luke 137
	onintr();
9469 ripley 138
    }
139
    R_CallBackHook();
45116 ripley 140
    if(R_Tcl_do) R_Tcl_do();
9469 ripley 141
}
142
 
64106 murdoch 143
void R_WaitEvent(void)
144
{
145
    if (!peekevent()) waitevent();
146
}
9469 ripley 147
 
64106 murdoch 148
 
9469 ripley 149
/*
150
 *  1) FATAL MESSAGES AT STARTUP
151
 */
152
 
43767 ripley 153
void R_Suicide(const char *s)
9469 ripley 154
{
155
    char  pp[1024];
156
 
32888 ripley 157
    snprintf(pp, 1024, _("Fatal error: %s\n"), s);
9469 ripley 158
    R_ShowMessage(pp);
159
    R_CleanUp(SA_SUICIDE, 2, 0);
160
}
161
 
162
/*
163
 *  2. CONSOLE I/O
164
 */
165
 
166
/*
167
 * We support 4 different type of input.
168
 * 1) from the gui console;
169
 * 2) from a character mode console (interactive);
170
 * 3) from a pipe under --ess, i.e, interactive.
171
 * 4) from a file or from a pipe (not interactive)
172
 *
173
 * Hence, it is better to have a different function for every
174
 * situation.
175
 * Same, it is true for output (but in this case, 2=3=4)
176
 *
177
 * BTW, 3 and 4 are different on input  since fgets,ReadFile...
178
 * "blocks" =>  (e.g.) you cannot give focus to the graphics device if
179
 * you are wating for input. For this reason, input is got in a different
180
 * thread
181
 *
182
 * All works in this way:
183
 * R_ReadConsole calls TrueReadConsole which points to:
184
 * case 1: GuiReadConsole
185
 * case 2 and 3: ThreadedReadConsole
186
 * case 4: FileReadConsole
187
 * ThreadedReadConsole wake up our 'reader thread' and wait until
188
 * a new line of input is available. The 'reader thread' uses
189
 * InThreadReadConsole to get it. InThreadReadConsole points to:
190
 * case 2: CharReadConsole
191
 * case 3: FileReadConsole
192
*/
193
 
194
/* Global variables */
43767 ripley 195
static int (*TrueReadConsole) (const char *, char *, int, int);
196
static int (*InThreadReadConsole) (const char *, char *, int, int);
197
static void (*TrueWriteConsole) (const char *, int);
198
static void (*TrueWriteConsoleEx) (const char *, int, int);
9469 ripley 199
HANDLE EhiWakeUp;
43767 ripley 200
static const char *tprompt;
201
static char *tbuf;
9469 ripley 202
static  int tlen, thist, lineavailable;
203
 
204
 /* Fill a text buffer with user typed console input. */
205
int
43767 ripley 206
R_ReadConsole(const char *prompt, unsigned char *buf, int len,
207
	      int addtohistory)
9469 ripley 208
{
209
    R_ProcessEvents();
210
    return TrueReadConsole(prompt, (char *) buf, len, addtohistory);
211
}
212
 
213
	/* Write a text buffer to the console. */
214
	/* All system output is filtered through this routine. */
215
 
43767 ripley 216
void R_WriteConsole(const char *buf, int len)
9469 ripley 217
{
218
    R_ProcessEvents();
40812 urbaneks 219
    if (TrueWriteConsole) TrueWriteConsole(buf, len);
220
    else TrueWriteConsoleEx(buf, len, 0);
9469 ripley 221
}
222
 
223
 
43767 ripley 224
void R_WriteConsoleEx(const char *buf, int len, int otype)
40812 urbaneks 225
{
226
    R_ProcessEvents();
227
    if (TrueWriteConsole) TrueWriteConsole(buf, len);
228
    else TrueWriteConsoleEx(buf, len, otype);
229
}
9469 ripley 230
 
40812 urbaneks 231
 
232
 
9469 ripley 233
/*1: from GUI console */
14670 ripley 234
int R_is_running = 0;
9469 ripley 235
 
236
void Rconsolesetwidth(int cols)
237
{
238
    if(R_is_running && setWidthOnResize)
239
	R_SetOptionWidth(cols);
240
}
241
 
242
static int
43767 ripley 243
GuiReadConsole(const char *prompt, char *buf, int len, int addtohistory)
9469 ripley 244
{
20824 ripley 245
    int res;
41883 ripley 246
    const char *NormalPrompt =
54049 ripley 247
	CHAR(STRING_ELT(GetOption1(install("prompt")), 0));
9469 ripley 248
 
249
    if(!R_is_running) {
250
	R_is_running = 1;
251
	Rconsolesetwidth(consolecols(RConsole));
252
    }
253
    ConsoleAcceptCmd = !strcmp(prompt, NormalPrompt);
20824 ripley 254
    res = consolereads(RConsole, prompt, buf, len, addtohistory);
9469 ripley 255
    ConsoleAcceptCmd = 0;
20824 ripley 256
    return !res;
9469 ripley 257
}
258
 
259
 
260
/* 2 and 3: reading in a thread */
261
 
262
 
263
/* 'Reader thread' main function */
264
static void __cdecl ReaderThread(void *unused)
265
{
45070 ripley 266
    while(1) {
267
	WaitForSingleObject(EhiWakeUp,INFINITE);
268
	tlen = InThreadReadConsole(tprompt,tbuf,tlen,thist);
269
	lineavailable = 1;
270
	PostThreadMessage(mainThreadId, 0, 0, 0);
271
    }
9469 ripley 272
}
273
 
274
static int
43767 ripley 275
ThreadedReadConsole(const char *prompt, char *buf, int len, int addtohistory)
9469 ripley 276
{
45070 ripley 277
    sighandler_t oldint,oldbreak;
278
    /*
279
     *   SIGINT/SIGBREAK when ESS is waiting for output are a real pain:
280
     *   they get processed after user hit <return>.
281
     *   The '^C\n' in raw Rterm is nice. But, do we really need it ?
282
     */
283
    oldint = signal(SIGINT, SIG_IGN);
284
    oldbreak = signal(SIGBREAK, SIG_IGN);
285
    mainThreadId = GetCurrentThreadId();
286
    lineavailable = 0;
287
    tprompt = prompt;
288
    tbuf = buf;
289
    tlen = len;
290
    thist = addtohistory;
291
    SetEvent(EhiWakeUp);
292
    while (1) {
64106 murdoch 293
	R_WaitEvent();
45070 ripley 294
	if (lineavailable) break;
295
	doevent();
45116 ripley 296
	if(R_Tcl_do) R_Tcl_do();
45070 ripley 297
    }
298
    lineavailable = 0;
299
    /* restore handler  */
45116 ripley 300
    signal(SIGINT, oldint);
301
    signal(SIGBREAK, oldbreak);
45070 ripley 302
    return tlen;
9469 ripley 303
}
304
 
305
 
306
/*2: from character console with getline (only used as InThreadReadConsole)*/
307
static int
43767 ripley 308
CharReadConsole(const char *prompt, char *buf, int len, int addtohistory)
9469 ripley 309
{
43767 ripley 310
    int res = getline(prompt, buf, len);
38967 ripley 311
    if (addtohistory) gl_histadd(buf);
312
    return !res;
9469 ripley 313
}
314
 
315
/*3: (as InThreadReadConsole) and 4: non-interactive */
32564 ripley 316
static void *cd = NULL;
317
 
9469 ripley 318
static int
43767 ripley 319
FileReadConsole(const char *prompt, char *buf, int len, int addhistory)
9469 ripley 320
{
32564 ripley 321
    int ll, err = 0;
38967 ripley 322
 
77228 maechler 323
    if (!R_NoEcho) {
9469 ripley 324
	fputs(prompt, stdout);
325
	fflush(stdout);
326
    }
40340 ripley 327
    if (fgets(buf, len, ifp ? ifp : stdin) == NULL) return 0;
32564 ripley 328
    /* translate if necessary */
329
    if(strlen(R_StdinEnc) && strcmp(R_StdinEnc, "native.enc")) {
38967 ripley 330
	size_t res, inb = strlen(buf), onb = len;
52804 ripley 331
	const char *ib = buf; 
332
	char obuf[len+1], *ob = obuf;
32564 ripley 333
	if(!cd) {
334
	    cd = Riconv_open("", R_StdinEnc);
63439 murdoch 335
	    if(cd == (void *)-1) error(_("encoding '%s' is not recognised"), R_StdinEnc);
32564 ripley 336
	}
337
	res = Riconv(cd, &ib, &inb, &ob, &onb);
338
	*ob = '\0';
38976 ripley 339
	err = (res == (size_t)(-1));
32564 ripley 340
	/* errors lead to part of the input line being ignored */
44722 ripley 341
	if(err) printf(_("<ERROR: re-encoding failure from encoding '%s'>\n"),
44113 ripley 342
		       R_StdinEnc);
41883 ripley 343
	strncpy(buf, obuf, len);
38967 ripley 344
    }
345
 
12256 pd 346
/* according to system.txt, should be terminated in \n, so check this
32564 ripley 347
   at eof or error */
41883 ripley 348
    ll = strlen(buf);
40340 ripley 349
    if ((err || feof(ifp ? ifp: stdin))
38967 ripley 350
	&& buf[ll - 1] != '\n' && ll < len) {
12256 pd 351
	buf[ll++] = '\n'; buf[ll] = '\0';
352
    }
38974 ripley 353
 
77228 maechler 354
    if (!R_Interactive && !R_NoEcho) {
9469 ripley 355
	fputs(buf, stdout);
53592 ripley 356
	fflush(stdout);
357
    }
9469 ripley 358
    return 1;
359
}
360
 
361
 
362
/* Rgui */
363
static void
43767 ripley 364
GuiWriteConsole(const char *buf,int len)
9469 ripley 365
{
32836 murdoch 366
    if (RConsole) consolewrites(RConsole, buf);
367
    else MessageBox(NULL, buf, "Console not found", MB_OK | MB_ICONEXCLAMATION);
9469 ripley 368
}
369
 
370
/* Rterm write */
371
static void
43767 ripley 372
TermWriteConsole(const char *buf, int len)
9469 ripley 373
{
374
    printf("%s", buf);
375
}
376
 
377
 
378
 
379
 
380
 
381
	/* Indicate that input is coming from the console */
382
 
44201 ripley 383
void R_ResetConsole(void)
9469 ripley 384
{
385
}
386
 
387
 
388
	/* Stdio support to ensure the console file buffer is flushed */
389
 
44201 ripley 390
void R_FlushConsole(void)
9469 ripley 391
{
45995 murdoch 392
    if (CharacterMode == RTerm && R_Interactive) fflush(stdout);
32836 murdoch 393
    else if (CharacterMode == RGui && RConsole) consoleflush(RConsole);
9469 ripley 394
}
395
 
396
 
397
	/* Reset stdin if the user types EOF on the console. */
398
 
44201 ripley 399
void R_ClearerrConsole(void)
9469 ripley 400
{
401
    if (CharacterMode == RTerm)  clearerr(stdin);
402
}
403
 
404
 
405
/*
406
 *  3) ACTIONS DURING (LONG) COMPUTATIONS
407
 */
408
 
38867 ripley 409
static void GuiBusy(int which)
9469 ripley 410
{
29220 ripley 411
    if (which == 1) gsetcursor(RConsole, WatchCursor);
412
    if (which == 0) gsetcursor(RConsole, ArrowCursor);
9469 ripley 413
}
414
 
38867 ripley 415
static void CharBusy(int which)
9469 ripley 416
{
417
}
418
 
419
void R_Busy(int which)
420
{
421
    my_R_Busy(which);
422
}
423
 
424
 
425
/*
426
 *  4) INITIALIZATION AND TERMINATION ACTIONS
427
 */
428
 
429
/*
430
   R_CleanUp is invoked at the end of the session to give the user the
431
   option of saving their data.
432
   If ask == SA_SAVEASK the user should be asked if possible (and this
433
   option should not occur in non-interactive use).
434
   If ask = SA_SAVE or SA_NOSAVE the decision is known.
435
   If ask = SA_DEFAULT use the SaveAction set at startup.
436
   In all these cases run .Last() unless quitting is cancelled.
437
   If ask = SA_SUICIDE, no save, no .Last, possibly other things.
438
 */
439
 
11155 ripley 440
void R_CleanUp(SA_TYPE saveact, int status, int runLast)
9469 ripley 441
{
442
    if(saveact == SA_DEFAULT) /* The normal case apart from R_Suicide */
443
	saveact = SaveAction;
444
 
445
    if(saveact == SA_SAVEASK) {
446
	if(R_Interactive) {
38485 murdoch 447
	    switch (R_YesNoCancel(G_("Save workspace image?"))) {
448
	    case YES:
449
		saveact = SA_SAVE;
450
		break;
451
	    case NO:
452
		saveact = SA_NOSAVE;
453
		break;
454
	    case CANCEL:
61956 ripley 455
		// There might be residual events with destroyed handles
456
		R_ProcessEvents();
38485 murdoch 457
		jump_to_toplevel();
458
		break;
459
 
9469 ripley 460
	    }
461
	} else saveact = SaveAction;
462
    }
463
 
464
    switch (saveact) {
465
    case SA_SAVE:
466
	if(runLast) R_dot_Last();
467
	if(R_DirtyImage) R_SaveGlobalEnv();
43882 ripley 468
	if (CharacterMode == RGui) {
33494 ripley 469
	    R_setupHistory(); /* re-read the history size and filename */
43882 ripley 470
	    wgl_savehistory(R_HistoryFile, R_HistorySize);
471
	} else if(R_Interactive && CharacterMode == RTerm) {
472
	    R_setupHistory(); /* re-read the history size and filename */
33494 ripley 473
	    gl_savehistory(R_HistoryFile, R_HistorySize);
474
	}
9469 ripley 475
	break;
476
    case SA_NOSAVE:
477
	if(runLast) R_dot_Last();
478
	break;
479
    case SA_SUICIDE:
480
    default:
481
	break;
482
    }
15884 luke 483
    R_RunExitFinalizers();
28991 murdoch 484
    editorcleanall();
9469 ripley 485
    CleanEd();
56032 ripley 486
    KillAllDevices(); /* Unix does not do this under SA_SUICIDE */
487
    AllDevicesKilled = TRUE; /* used in devWindows.c to inhibit callbacks */
55668 ripley 488
    R_CleanTempDir(); /* changes directory */
27590 murdoch 489
    if (R_Interactive && CharacterMode == RTerm)
12976 pd 490
	SetConsoleTitle(oldtitle);
9469 ripley 491
    if (R_CollectWarnings && saveact != SA_SUICIDE
56032 ripley 492
	&& CharacterMode == RTerm)   /* no point in doing this for Rgui
493
					as the console is about to close */
494
	PrintWarnings();        /* from device close and (if run) .Last */
9469 ripley 495
    app_cleanup();
32836 murdoch 496
    RConsole = NULL;
69009 ripley 497
    // Add some protection against calling this more than once:
498
    // caused by signals on Unix, so maybe cannot happen here.
499
    if(ifp) { 
500
	fclose(ifp);    /* input file from -f or --file= */
501
	ifp = NULL; 
502
    }
503
    if(ifile[0]) {
504
	unlink(ifile); /* input file from -e */
69066 ripley 505
	ifile[0] = '\0';
69009 ripley 506
    }
9469 ripley 507
    exit(status);
508
}
509
 
510
/*
511
 *  7) PLATFORM DEPENDENT FUNCTIONS
512
 */
513
 
514
    /*
515
       This function can be used to display the named files with the
516
       given titles and overall title.  On GUI platforms we could
517
       use a read-only window to display the result.  Here we just
518
       make up a temporary file and invoke a pager on it.
519
    */
520
 
521
    /*
522
     *     nfile   = number of files
523
     *     file    = array of filenames
33099 ripley 524
     *     headers = the 'headers' args of file.show. Printed before each file.
525
     *     wtitle  = title for window: the 'title' arg of file.show
9469 ripley 526
     *     del     = flag for whether files should be deleted after use
527
     *     pager   = pager to be used.
528
     */
529
 
44016 ripley 530
 
531
extern FILE *R_wfopen(const wchar_t *filename, const wchar_t *mode);
532
extern size_t Rf_utf8towcs(wchar_t *wc, const char *s, size_t n);
533
 
43767 ripley 534
int R_ShowFiles(int nfile, const char **file, const char **headers,
535
		const char *wtitle, Rboolean del, const char *pager)
9469 ripley 536
{
73584 kalibera 537
    int   i, ll;
9469 ripley 538
    char  buf[1024];
539
 
540
    if (nfile > 0) {
541
	if (pager == NULL || strlen(pager) == 0)
542
	    pager = "internal";
543
	for (i = 0; i < nfile; i++) {
29215 ripley 544
	    if(!access(file[i], R_OK)) {
9469 ripley 545
		if (!strcmp(pager, "internal")) {
46842 ripley 546
		    newpager(wtitle, file[i], CE_NATIVE, headers[i], del);
9469 ripley 547
		} else if (!strcmp(pager, "console")) {
548
		    size_t len;
44016 ripley 549
		    FILE *f;
46842 ripley 550
		    f = R_fopen(file[i], "rt");
9469 ripley 551
		    if(f) {
552
			while((len = fread(buf, 1, 1023, f))) {
553
			    buf[len] = '\0';
554
			    R_WriteConsole(buf, strlen(buf));
555
			}
556
			fclose(f);
46842 ripley 557
			if (del) DeleteFile(file[i]);
51767 ripley 558
			/* add a blank line */
559
			R_WriteConsole("", 0);
9469 ripley 560
		    }
561
		    else {
45070 ripley 562
			snprintf(buf, 1024,
44796 ripley 563
				 _("cannot open file '%s': %s"),
44795 ripley 564
				 file[i], strerror(errno));
9469 ripley 565
			warning(buf);
566
		    }
567
		} else {
45070 ripley 568
		    /* Quote path if necessary */
32704 ripley 569
		    if(pager[0] != '"' && Rf_strchr(pager, ' '))
25313 ripley 570
			snprintf(buf, 1024, "\"%s\" \"%s\"", pager, file[i]);
10656 ripley 571
		    else
25313 ripley 572
			snprintf(buf, 1024, "%s \"%s\"", pager, file[i]);
73584 kalibera 573
		    ll = runcmd(buf, CE_NATIVE, 0, 1, NULL, NULL, NULL);
73609 kalibera 574
		    if (ll == NOLAUNCH) warning(runerror());
9469 ripley 575
		}
576
	    } else {
33297 ripley 577
		snprintf(buf, 1024,
578
			 _("file.show(): file '%s' does not exist\n"),
25313 ripley 579
			 file[i]);
9469 ripley 580
		warning(buf);
581
	    }
582
	}
583
	return 0;
584
    }
585
    return 1;
586
}
587
 
588
 
28991 murdoch 589
    /*
590
       This function can be used to open the named files in text editors, with the
29051 murdoch 591
       given titles and overall title.
592
       If the file does not exist then the editor should be opened to create a new file.
28991 murdoch 593
    */
9469 ripley 594
 
28991 murdoch 595
    /*
596
     *     nfile   = number of files
597
     *     file    = array of filenames
598
     *     editor  = editor to be used.
599
     */
600
 
44016 ripley 601
/* As from R 2.7.0 we assume file, editor are in UTF-8 */
43760 ripley 602
int R_EditFiles(int nfile, const char **file, const char **title,
603
		const char *editor)
28991 murdoch 604
{
73584 kalibera 605
    int   i, ll;
28991 murdoch 606
    char  buf[1024];
607
 
608
    if (nfile > 0) {
609
	if (editor == NULL || strlen(editor) == 0)
610
	    editor = "internal";
611
	for (i = 0; i < nfile; i++) {
612
	    if (!strcmp(editor, "internal")) {
44016 ripley 613
		Rgui_Edit(file[i], CE_UTF8, title[i], 0);
28991 murdoch 614
	    } else {
615
		/* Quote path if necessary */
32704 ripley 616
		if (editor[0] != '"' && Rf_strchr(editor, ' '))
28991 murdoch 617
		    snprintf(buf, 1024, "\"%s\" \"%s\"", editor, file[i]);
618
		else
619
		    snprintf(buf, 1024, "%s \"%s\"", editor, file[i]);
73584 kalibera 620
		ll = runcmd(buf, CE_UTF8, 0, 1, NULL, NULL, NULL);
73609 kalibera 621
		if (ll == NOLAUNCH) warning(runerror());
28991 murdoch 622
	    }
623
 
624
	}
625
	return 0;
626
    }
627
    return 1;
628
}
629
 
46842 ripley 630
#if 0
9469 ripley 631
/* Prompt the user for a file name.  Return the length of */
632
/* the name typed.  On Gui platforms, this should bring up */
633
/* a dialog box so a user can choose files that way. */
634
 
635
extern int DialogSelectFile(char *buf, int len); /* from rui.c */
636
 
637
int R_ChooseFile(int new, char *buf, int len)
638
{
44016 ripley 639
    return DialogSelectFile(buf, len);
9469 ripley 640
}
46842 ripley 641
#endif
9469 ripley 642
 
38485 murdoch 643
/* code for R_ShowMessage, R_YesNoCancel */
9469 ripley 644
 
43767 ripley 645
void (*pR_ShowMessage)(const char *s);
646
void R_ShowMessage(const char *s)
9469 ripley 647
{
648
    (*pR_ShowMessage)(s);
649
}
650
 
651
 
43767 ripley 652
static void char_message(const char *s)
9469 ripley 653
{
654
    if (!s) return;
23258 ripley 655
    if (R_Consolefile) {
656
	/* flush out standard output in case it uses R_Consolefile */
657
	if (R_Outputfile) fflush(R_Outputfile);
658
	fprintf(R_Consolefile, "%s\n", s);
659
	fflush(R_Consolefile);
660
    } else R_WriteConsole(s, strlen(s));
9469 ripley 661
}
662
 
43767 ripley 663
static int char_YesNoCancel(const char *s)
9469 ripley 664
{
665
    char  ss[128];
666
    unsigned char a[3];
667
 
62583 ripley 668
    snprintf(ss, 128, "%s [y/n/c]: ", s);
9469 ripley 669
    R_ReadConsole(ss, a, 3, 0);
670
    switch (a[0]) {
671
    case 'y':
672
    case 'Y':
673
	return YES;
674
    case 'n':
675
    case 'N':
676
	return NO;
677
    default:
678
	return CANCEL;
679
    }
680
}
681
 
682
 
683
	/*--- Initialization Code ---*/
684
 
685
static char RHome[MAX_PATH + 7];
686
static char UserRHome[MAX_PATH + 7];
51536 ripley 687
extern char *getRHOME(int), *getRUser(void); /* in rhome.c */
44201 ripley 688
void R_setStartTime(void);
9469 ripley 689
 
690
 
691
void R_SetWin32(Rstart Rp)
692
{
35898 ripley 693
    int dummy;
694
 
35904 ripley 695
    {
696
	/* Idea here is to ask about the memory block an automatic
697
	   variable is in.  VirtualQuery rounds down to the beginning
698
	   of the page, and tells us where the allocation started and
699
	   how many bytes the pages go up */
35902 ripley 700
 
35904 ripley 701
	MEMORY_BASIC_INFORMATION buf;
36969 ripley 702
	uintptr_t bottom, top;
35904 ripley 703
 
704
	VirtualQuery(&dummy, &buf, sizeof(buf));
36969 ripley 705
	bottom = (uintptr_t) buf.AllocationBase;
706
	top = (uintptr_t) buf.BaseAddress + buf.RegionSize;
35904 ripley 707
	/* printf("stackbase %lx, size %lx\n", top, top-bottom); */
708
	R_CStackStart = top;
709
	R_CStackLimit = top - bottom;
72635 kalibera 710
 
711
	/* The stack detection above is not precise, in fact the stack will
712
	   not be able to grow that large. As documented, at least one page
713
	   from the space will be used as a guard page. Starting from the
714
	   top (high address), the stack is formed by committed area, the
715
	   guard page, and reserved area. The guard is used for on-demand
716
	   growing of the committed area and shrinking of the reserve.
717
	   Experiments show that the reserve would not shrink to less than
718
	   2 pages (Win7, 32bit). This is not documented and was not tested 
719
	   in other versions of Windows.*/
720
	if (R_CStackLimit > 4*4096)
721
	    R_CStackLimit -= 4*4096;
722
 
723
	/* setup_Rmainloop includes (disabled) code to test stack detection */
35904 ripley 724
    }
38967 ripley 725
 
35898 ripley 726
    R_CStackDir = 1;
9469 ripley 727
    R_Home = Rp->rhome;
33040 ripley 728
    if(strlen(R_Home) >= MAX_PATH) R_Suicide("Invalid R_HOME");
62583 ripley 729
    snprintf(RHome, MAX_PATH+7, "R_HOME=%s", R_Home);
55026 ripley 730
    for (char *p = RHome; *p; p++) if (*p == '\\') *p = '/';
9469 ripley 731
    putenv(RHome);
732
    strcpy(UserRHome, "R_USER=");
733
    strcat(UserRHome, Rp->home);
734
    putenv(UserRHome);
46445 murdoch 735
 
736
    if( !getenv("HOME") ) {
737
	strcpy(UserRHome, "HOME=");
738
	strcat(UserRHome, getRUser());
739
	putenv(UserRHome);
74528 kalibera 740
    }
741
    putenv("MSYS2_ENV_CONV_EXCL=R_ARCH");
9469 ripley 742
 
70086 murdoch 743
 
744
    /* This is here temporarily while the GCC version is chosen */
745
    char gccversion[30];
746
    snprintf(gccversion, 30, "R_COMPILED_BY=gcc %d.%d.%d", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__);
747
    putenv(gccversion);
748
 
42059 murdoch 749
    /* Rterm and Rgui set CharacterMode during startup, then set Rp->CharacterMode
45070 ripley 750
       from it in cmdlineoptions().  Rproxy never calls cmdlineoptions, so we need the
42059 murdoch 751
       line below */
45070 ripley 752
 
42059 murdoch 753
    CharacterMode = Rp->CharacterMode;
35902 ripley 754
    switch(CharacterMode) {
9469 ripley 755
    case RGui:
756
	R_GUIType = "Rgui";
757
	break;
758
    case RTerm:
759
	R_GUIType = "RTerm";
760
	break;
761
    default:
762
	R_GUIType = "unknown";
763
    }
764
    TrueReadConsole = Rp->ReadConsole;
765
    TrueWriteConsole = Rp->WriteConsole;
40812 urbaneks 766
    TrueWriteConsoleEx = Rp->WriteConsoleEx;
9469 ripley 767
    R_CallBackHook = Rp->CallBack;
31698 ripley 768
    pR_ShowMessage = Rp->ShowMessage;
769
    R_YesNoCancel = Rp->YesNoCancel;
770
    my_R_Busy = Rp->Busy;
21550 ripley 771
    /* Process R_HOME/etc/Renviron.site, then
27590 murdoch 772
       .Renviron or ~/.Renviron, if it exists.
11533 ripley 773
       Only used here in embedded versions */
21550 ripley 774
    if(!Rp->NoRenviron) {
775
	process_site_Renviron();
15427 hornik 776
	process_user_Renviron();
21550 ripley 777
    }
37410 ripley 778
    Rwin_fpset();  /* in extra.c */
9469 ripley 779
}
780
 
781
 
782
/* Remove and process NAME=VALUE command line arguments */
783
 
43767 ripley 784
static void Putenv(const char *str)
11533 ripley 785
{
786
    char *buf;
787
    buf = (char *) malloc((strlen(str) + 1) * sizeof(char));
788
    if(!buf) R_ShowMessage("allocation failure in reading Renviron");
789
    strcpy(buf, str);
790
    putenv(buf);
45070 ripley 791
    /* no free here: storage remains in use */
11533 ripley 792
}
793
 
794
 
9469 ripley 795
static void env_command_line(int *pac, char **argv)
796
{
797
    int ac = *pac, newac = 1; /* Remember argv[0] is process name */
798
    char **av = argv;
42707 ripley 799
    Rboolean hadE = FALSE;
9469 ripley 800
 
42707 ripley 801
    /* We don't want to parse -e expressions */
9469 ripley 802
    while(--ac) {
803
	++av;
42707 ripley 804
	if(strcmp(*av, "-e") == 0) {
805
	    hadE = TRUE;
45070 ripley 806
	    argv[newac++] = *av;
42707 ripley 807
	    continue;
808
	}
809
	if(!hadE && **av != '-' && Rf_strchr(*av, '='))
9469 ripley 810
	    Putenv(*av);
811
	else
812
	    argv[newac++] = *av;
42707 ripley 813
	hadE = FALSE;
9469 ripley 814
    }
815
    *pac = newac;
816
}
817
 
27089 ripley 818
char *PrintUsage(void)
819
{
820
    static char msg[5000];
821
    char msg0[] =
52419 ripley 822
	"Start R, a system for statistical computation and graphics, with the\nspecified options\n\nEnvVars: Environmental variables can be set by NAME=value strings\n\nOptions:\n  -h, --help            Print usage message and exit\n  --version             Print version info and exit\n  --encoding=enc        Specify encoding to be used for stdin\n  --encoding enc        ditto\n  --save                Do save workspace at the end of the session\n  --no-save             Don't save it\n",
27590 murdoch 823
	msg1[] =
77363 kalibera 824
	"  --no-environ          Don't read the site and user environment files\n  --no-site-file        Don't read the site-wide Rprofile\n  --no-init-file        Don't read the .Rprofile or ~/.Rprofile files\n  --restore             Do restore previously saved objects at startup\n  --no-restore-data     Don't restore previously saved objects\n  --no-restore-history  Don't restore the R history file\n  --no-restore          Don't restore anything\n  --workspace=file      Workspace to be restored\n",
27590 murdoch 825
	msg2[] =
57136 ripley 826
	"  --vanilla             Combine --no-save, --no-restore, --no-site-file,\n                          --no-init-file and --no-environ\n",
27089 ripley 827
	msg2b[] =
45070 ripley 828
	"  --max-mem-size=N      Set limit for memory to be used by R\n  --max-ppsize=N        Set max size of protect stack to N\n",
27089 ripley 829
	msg3[] =
77363 kalibera 830
	"  -q, --quiet           Don't print startup message\n  --silent              Same as --quiet\n  --no-echo             Make R run as quietly as possible\n  --verbose             Print more information about progress\n  --args                Skip the rest of the command line\n",
27590 murdoch 831
	msg4[] =
46118 ripley 832
	"  --ess                 Don't use getline for command-line editing\n                          and assert interactive use\n  -f file               Take input from 'file'\n  --file=file           ditto\n  -e expression         Use 'expression' as input\n\nOne or more -e options can be used, but not together with -f or --file\n",
833
	msg5[] = "\nAn argument ending in .RData (in any case) is taken as the path\nto the workspace to be restored (and implies --restore)";
27590 murdoch 834
    if(CharacterMode == RTerm)
27089 ripley 835
	strcpy(msg, "Usage: Rterm [options] [< infile] [> outfile] [EnvVars]\n\n");
836
    else strcpy(msg, "Usage: Rgui [options] [EnvVars]\n\n");
837
    strcat(msg, msg0);
838
    strcat(msg, msg1);
839
    strcat(msg, msg2);
840
    strcat(msg, msg2b);
841
    strcat(msg, msg3);
842
    if(CharacterMode == RTerm) strcat(msg, msg4);
46118 ripley 843
    strcat(msg, msg5);
40396 ripley 844
    strcat(msg, "\n");
27089 ripley 845
    return msg;
846
}
847
 
44201 ripley 848
void R_setupHistory(void)
33494 ripley 849
{
850
    int value, ierr;
851
    char *p;
27089 ripley 852
 
33494 ripley 853
    if ((R_HistoryFile = getenv("R_HISTFILE")) == NULL)
45070 ripley 854
	R_HistoryFile = ".Rhistory";
33494 ripley 855
    R_HistorySize = 512;
856
    if ((p = getenv("R_HISTSIZE"))) {
45070 ripley 857
	value = R_Decode2Long(p, &ierr);
858
	if (ierr != 0 || value < 0)
859
	    R_ShowMessage("WARNING: invalid R_HISTSIZE ignored;");
860
	else
861
	    R_HistorySize = value;
33494 ripley 862
    }
863
}
14488 ripley 864
 
46078 ripley 865
#include <sys/stat.h>
866
static int isDir(char *path)
867
{
868
    struct stat sb;
869
    int isdir = 0;
870
    if(!path) return 0;
871
    if(stat(path, &sb) == 0) {
872
	isdir = (sb.st_mode & S_IFDIR) > 0; /* is a directory */
873
	/* We want to know if the directory is writable by this user,
874
	   which mode does not tell us */
875
	isdir &= (access(path, W_OK) == 0);
876
    }
877
    return isdir;
878
}
879
 
77363 kalibera 880
static Rboolean use_workspace(Rstart Rp, char *name, Rboolean usedRdata)
881
{
882
    char s[1024];
883
    char path[MAX_PATH];
884
    char *p;
885
 
886
    if(!usedRdata) {
887
	if (strlen(name) >= MAX_PATH) {
888
	     /* if generated by Windows it must fit */
889
	    snprintf(s, 1024, _("Workspace name '%s' is too long\n"), name);
890
	    R_ShowMessage(s);
891
	} else {
892
	    set_workspace_name(name);
893
	    strcpy(path, name);
894
	    for (p = path; *p; p++) if (*p == '\\') *p = '/';
895
	    p = Rf_strrchr(path, '/');
896
	    if(p) {
897
		*p = '\0';
898
		chdir(path);
899
	    }
900
	    usedRdata = TRUE;
901
	    Rp->RestoreAction = SA_RESTORE;
902
	    return TRUE;
903
	}
904
    } else {
905
	snprintf(s, 1024, _("ARGUMENT '%s' __ignored__\n"), name);
906
	R_ShowMessage(s);
907
    }
908
    return FALSE;
909
}
910
 
9469 ripley 911
int cmdlineoptions(int ac, char **av)
912
{
11007 ripley 913
    int   i, ierr;
20094 ripley 914
    R_size_t value;
31689 ripley 915
    char *p;
40396 ripley 916
    char  s[1024], cmdlines[10000];
42716 ripley 917
    R_size_t Virtual;
9469 ripley 918
    structRstart rstart;
919
    Rstart Rp = &rstart;
25603 ripley 920
    Rboolean usedRdata = FALSE, processing = TRUE;
9469 ripley 921
 
21550 ripley 922
    /* ensure R_Home gets set early: we are in rgui or rterm here */
51536 ripley 923
    R_Home = getRHOME(3);
33001 ripley 924
    /* need this for moduleCdynload for iconv.dll */
925
    InitFunctionHashing();
62584 ripley 926
    snprintf(RHome, MAX_PATH+7, "R_HOME=%s", R_Home);
33001 ripley 927
    putenv(RHome);
59833 ripley 928
    BindDomain(R_Home);
27590 murdoch 929
 
9469 ripley 930
    R_setStartTime();
931
 
932
    /* Store the command line arguments before they are processed
933
       by the different option handlers. We do this here so that
934
       we get all the name=value pairs. Otherwise these will
935
       have been removed by the time we get to call
936
       R_common_command_line().
45070 ripley 937
    */
29748 ripley 938
    R_set_command_line_arguments(ac, av);
9469 ripley 939
 
940
 
11168 ripley 941
    /* set defaults for R_max_memory. This is set here so that
942
       embedded applications get no limit */
45070 ripley 943
    {
42715 ripley 944
	MEMORYSTATUSEX ms;
43865 murdoch 945
	ms.dwLength = sizeof(MEMORYSTATUSEX);
42715 ripley 946
	GlobalMemoryStatusEx(&ms); /* Win2k or later */
42716 ripley 947
	Virtual = ms.ullTotalVirtual; /* uint64 = DWORDLONG */
65805 ripley 948
#ifdef _WIN64
42716 ripley 949
	R_max_memory = ms.ullTotalPhys;
42715 ripley 950
#else
43328 ripley 951
	R_max_memory = min(Virtual - 512*Mega, ms.ullTotalPhys);
42715 ripley 952
#endif
27590 murdoch 953
 
43328 ripley 954
	/* need enough to start R, with some head room */
955
	R_max_memory = max(32 * Mega, R_max_memory);
956
    }
957
 
9469 ripley 958
    R_DefParams(Rp);
959
    Rp->CharacterMode = CharacterMode;
960
    for (i = 1; i < ac; i++)
961
	if (!strcmp(av[i], "--no-environ") || !strcmp(av[i], "--vanilla"))
45070 ripley 962
	    Rp->NoRenviron = TRUE;
74844 kalibera 963
	else if (!strcmp(av[i], "--cd-to-userdocs")) {
964
	    /* This is used in shortcuts created by the installer. Previously, the
965
	       installer resolved the user documents folder at installation time,
966
	       but that is not good for installation under SCCM/system context where
967
	       it resolved to documents folder in systemprofile. This has do be done
968
	       before process_user_Renviron(), because user .Renviron may be read from
969
	       the current directory, which is expected to be userdocs. */
970
	    TCHAR mydocs[MAX_PATH + 1];
971
	    if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PERSONAL|CSIDL_FLAG_CREATE,
972
					  NULL, 0, mydocs))) 
973
		SetCurrentDirectory(mydocs);
974
	}
9469 ripley 975
 
976
    Rp->CallBack = R_DoNothing;
31698 ripley 977
    /* Here so that --ess and similar can change */
9469 ripley 978
    InThreadReadConsole = NULL;
979
    if (CharacterMode == RTerm) {
23258 ripley 980
	if (isatty(0) && isatty(1)) {
10470 maechler 981
	    Rp->R_Interactive = TRUE;
9469 ripley 982
	    Rp->ReadConsole = ThreadedReadConsole;
45070 ripley 983
	    InThreadReadConsole = CharReadConsole;
76905 kalibera 984
	} else if (R_is_redirection_tty(0) && R_is_redirection_tty(1)) {
76988 kalibera 985
	    /* Note it is not currently possible to use line editing with Msys2
986
	       terminals such as mintty, because we cannot disable buffering in
987
	       the terminal. One can only do that from applications linked
988
	       against the Cygwin runtime, but R is linked against Msvcrt
76998 kalibera 989
	       via Mingw and using multiple runtimes is not possible.
990
 
991
	       Msys2/cygwin is handled in AppMain() by re-executing using
992
	       winpty. This branch is taken when winpty is not available.
993
	    */
76905 kalibera 994
	    Rp->R_Interactive = TRUE;
995
	    Rp->ReadConsole = ThreadedReadConsole;
996
	    InThreadReadConsole = FileReadConsole;
997
	    setvbuf(stdout, NULL, _IONBF, 0);
9469 ripley 998
	} else {
10470 maechler 999
	    Rp->R_Interactive = FALSE;
9469 ripley 1000
	    Rp->ReadConsole = FileReadConsole;
1001
	}
24886 ripley 1002
	/* Windows 95/98/ME have a shell that cannot redirect stderr,
1003
	   so don't use that on those OSes */
1004
	{
1005
	    OSVERSIONINFO verinfo;
45070 ripley 1006
	    verinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
24886 ripley 1007
	    GetVersionEx(&verinfo);
1008
	    switch(verinfo.dwPlatformId) {
1009
	    case VER_PLATFORM_WIN32_WINDOWS:
1010
		R_Consolefile = stdout; /* used for errors */
1011
		break;
1012
	    default:
1013
		R_Consolefile = stderr; /* used for errors */
1014
	    }
1015
	}
23294 ripley 1016
	R_Consolefile = stderr; /* used for errors */
9469 ripley 1017
	R_Outputfile = stdout;  /* used for sink-able output */
45070 ripley 1018
	Rp->WriteConsole = TermWriteConsole;
31698 ripley 1019
	Rp->ShowMessage = char_message;
1020
	Rp->YesNoCancel = char_YesNoCancel;
1021
	Rp->Busy = CharBusy;
9469 ripley 1022
    } else {
10470 maechler 1023
	Rp->R_Interactive = TRUE;
9469 ripley 1024
	Rp->ReadConsole = GuiReadConsole;
1025
	Rp->WriteConsole = GuiWriteConsole;
43847 ripley 1026
	Rp->ShowMessage = askok;
1027
	Rp->YesNoCancel = askyesnocancel;
31698 ripley 1028
	Rp->Busy = GuiBusy;
9469 ripley 1029
    }
1030
 
31698 ripley 1031
    pR_ShowMessage = Rp->ShowMessage; /* used here */
9469 ripley 1032
    TrueWriteConsole = Rp->WriteConsole;
45070 ripley 1033
    /* Rp->WriteConsole is guaranteed to be set above,
42707 ripley 1034
       so we know WriteConsoleEx is not used */
9469 ripley 1035
    R_CallBackHook = Rp->CallBack;
1036
 
1037
    /* process environment variables
1038
     * precedence:  command-line, .Renviron, inherited
1039
     */
1040
    if(!Rp->NoRenviron) {
21550 ripley 1041
	process_site_Renviron();
15427 hornik 1042
	process_user_Renviron();
10470 maechler 1043
	Rp->NoRenviron = TRUE;
74905 luke 1044
 
1045
	/* allow for R_MAX_[VN]SIZE and R_[VN]SIZE in user/site Renviron */
1046
	R_SizeFromEnv(Rp);
9469 ripley 1047
    }
1048
    env_command_line(&ac, av);
1049
 
1050
    R_common_command_line(&ac, av, Rp);
1051
 
68629 murdoch 1052
    char *q = getenv("R_MAX_MEM_SIZE");
59142 ripley 1053
    if (q && q[0]) {
1054
	value = R_Decode2Long(q, &ierr);
1055
	if(ierr || value < 32 * Mega || value > Virtual) {
62583 ripley 1056
	    snprintf(s, 1024,
1057
		     _("WARNING: R_MAX_MEM_SIZE value is invalid: ignored\n"));
59142 ripley 1058
	    R_ShowMessage(s);
1059
	} else R_max_memory = value;
1060
    }
1061
 
40396 ripley 1062
    cmdlines[0] = '\0';
9469 ripley 1063
    while (--ac) {
25603 ripley 1064
	if (processing && **++av == '-') {
28410 ripley 1065
	    if (!strcmp(*av, "--help") || !strcmp(*av, "-h")) {
27089 ripley 1066
		R_ShowMessage(PrintUsage());
1067
		exit(0);
73683 kalibera 1068
	    } else if (!strcmp(*av, "--cd-to-userdocs")) {
74844 kalibera 1069
		/* handled above before processing Renviron */
73683 kalibera 1070
	    } else if (!strcmp(*av, "--no-environ")) {
10470 maechler 1071
		Rp->NoRenviron = TRUE;
9469 ripley 1072
	    } else if (!strcmp(*av, "--ess")) {
1073
/* Assert that we are interactive even if input is from a file */
10470 maechler 1074
		Rp->R_Interactive = TRUE;
9469 ripley 1075
		Rp->ReadConsole = ThreadedReadConsole;
45070 ripley 1076
		InThreadReadConsole = FileReadConsole;
46005 ripley 1077
		setvbuf(stdout, NULL, _IONBF, 0);
16578 ripley 1078
	    } else if (!strcmp(*av, "--internet2")) {
68982 ripley 1079
/*	        This is now the default */
9469 ripley 1080
	    } else if (!strcmp(*av, "--mdi")) {
1081
		MDIset = 1;
1082
	    } else if (!strcmp(*av, "--sdi") || !strcmp(*av, "--no-mdi")) {
1083
		MDIset = -1;
11007 ripley 1084
	    } else if (!strncmp(*av, "--max-mem-size", 14)) {
1085
		if(strlen(*av) < 16) {
1086
		    ac--; av++; p = *av;
1087
		}
1088
		else
1089
		    p = &(*av)[15];
1090
		if (p == NULL) {
32888 ripley 1091
		    R_ShowMessage(_("WARNING: no max-mem-size given\n"));
11007 ripley 1092
		    break;
1093
		}
20094 ripley 1094
		value = R_Decode2Long(p, &ierr);
11007 ripley 1095
		if(ierr) {
1096
		    if(ierr < 0)
62583 ripley 1097
			snprintf(s, 1024,
1098
				 _("WARNING: --max-mem-size value is invalid: ignored\n"));
11007 ripley 1099
		    else
62583 ripley 1100
			snprintf(s, 1024,
1101
				 _("WARNING: --max-mem-size=%lu%c: too large and ignored\n"),
36413 ripley 1102
				(unsigned long) value,
42715 ripley 1103
				(ierr == 1) ? 'M': ((ierr == 2) ? 'K': 'G'));
11007 ripley 1104
		    R_ShowMessage(s);
37127 ripley 1105
		} else if (value < 32 * Mega) {
62583 ripley 1106
		    snprintf(s, 1024,
1107
			     _("WARNING: --max-mem-size=%4.1fM: too small and ignored\n"),
1108
			     value/(1024.0 * 1024.0));
11007 ripley 1109
		    R_ShowMessage(s);
42715 ripley 1110
		} else if (value > Virtual) {
62583 ripley 1111
		    snprintf(s, 1024,
1112
			     _("WARNING: --max-mem-size=%4.0fM: too large and taken as %uM\n"),
1113
			     value/(1024.0 * 1024.0),
1114
			     (unsigned int) (Virtual/(1024.0 * 1024.0)));
42715 ripley 1115
		    R_max_memory = Virtual;
36413 ripley 1116
		    R_ShowMessage(s);
11007 ripley 1117
		} else
1118
		    R_max_memory = value;
27590 murdoch 1119
	    } else if(!strcmp(*av, "--debug")) {
31698 ripley 1120
		DebugMenuitem = TRUE;
28138 murdoch 1121
		breaktodebugger();
25603 ripley 1122
	    } else if(!strcmp(*av, "--args")) {
1123
		break;
40340 ripley 1124
	    } else if(CharacterMode == RTerm && !strcmp(*av, "-f")) {
1125
		ac--; av++;
63437 murdoch 1126
		if (!ac) {
1127
		    snprintf(s, 1024,
1128
			    _("option '%s' requires an argument"),
1129
			    "-f");
1130
		    R_Suicide(s);
1131
		}
40340 ripley 1132
		Rp->R_Interactive = FALSE;
1133
		Rp->ReadConsole = FileReadConsole;
40349 ripley 1134
		if(strcmp(*av, "-")) {
1135
		    ifp = R_fopen(*av, "r");
1136
		    if(!ifp) {
45070 ripley 1137
			snprintf(s, 1024,
1138
				 _("cannot open file '%s': %s"),
44795 ripley 1139
				 *av, strerror(errno));
40349 ripley 1140
			R_Suicide(s);
1141
		    }
40340 ripley 1142
		}
1143
	    } else if(CharacterMode == RTerm && !strncmp(*av, "--file=", 7)) {
1144
		Rp->R_Interactive = FALSE;
1145
		Rp->ReadConsole = FileReadConsole;
40349 ripley 1146
		if(strcmp((*av)+7, "-")) {
1147
		    ifp = R_fopen( (*av)+7, "r");
1148
		    if(!ifp) {
45070 ripley 1149
			snprintf(s, 1024,
1150
				 _("cannot open file '%s': %s"),
44795 ripley 1151
				 (*av)+7, strerror(errno));
40349 ripley 1152
			R_Suicide(s);
1153
		    }
40340 ripley 1154
		}
77363 kalibera 1155
	    } else if (!strncmp(*av, "--workspace=", 12)) {
1156
		usedRdata = use_workspace(Rp, *av + 12, usedRdata);
40396 ripley 1157
	    } else if(CharacterMode == RTerm && !strcmp(*av, "-e")) {
1158
		ac--; av++;
63514 ripley 1159
		if (!ac || !strlen(*av)) {
63437 murdoch 1160
		    snprintf(s, 1024,
63514 ripley 1161
			    _("option '%s' requires a non-empty argument"),
63437 murdoch 1162
			    "-e");
1163
		    R_Suicide(s);
1164
		}
40396 ripley 1165
		if(strlen(cmdlines) + strlen(*av) + 2 <= 10000) {
1166
		    strcat(cmdlines, *av);
1167
		    strcat(cmdlines, "\n");
1168
		} else {
1169
		    snprintf(s, 1024, _("WARNING: '-e %s' omitted as input is too long\n"), *av);
1170
		    R_ShowMessage(s);
45070 ripley 1171
		}
9469 ripley 1172
	    } else {
33297 ripley 1173
		snprintf(s, 1024, _("WARNING: unknown option '%s'\n"), *av);
9469 ripley 1174
		R_ShowMessage(s);
1175
	    }
1176
	} else {
46118 ripley 1177
	    /* Look for *.RData, as given by drag-and-drop 
1178
	       and file association */
14488 ripley 1179
 
77363 kalibera 1180
	    if (strlen(*av) >= 6 && stricmp(*av+strlen(*av)-6, ".RData") == 0)
1181
		usedRdata = use_workspace(Rp, *av, usedRdata);
9469 ripley 1182
	}
1183
    }
40396 ripley 1184
    if(strlen(cmdlines)) {
1185
	if(ifp) R_Suicide(_("cannot use -e with -f or --file"));
1186
	Rp->R_Interactive = FALSE;
1187
	Rp->ReadConsole = FileReadConsole;
46078 ripley 1188
	{
1189
	    char *tm;
1190
	    tm = getenv("TMPDIR");
1191
	    if (!isDir(tm)) {
1192
		tm = getenv("TMP");
1193
		if (!isDir(tm)) {
1194
		    tm = getenv("TEMP");
1195
		    if (!isDir(tm))
1196
			tm = getenv("R_USER"); /* this one will succeed */
1197
		}
1198
	    }
53070 ripley 1199
	    /* in case getpid() is not unique -- has been seen under Windows */
62583 ripley 1200
	    snprintf(ifile, 1024, "%s/Rscript%x%x", tm, getpid(), 
1201
		     (unsigned int) GetTickCount());
46078 ripley 1202
	    ifp = fopen(ifile, "w+b");
1203
	    if(!ifp) R_Suicide(_("creation of tmpfile failed -- set TMPDIR suitably?"));
1204
	}
40396 ripley 1205
	fwrite(cmdlines, strlen(cmdlines)+1, 1, ifp);
1206
	fflush(ifp);
1207
	rewind(ifp);
1208
    }
1209
    if (ifp && Rp->SaveAction != SA_SAVE) Rp->SaveAction = SA_NOSAVE;
1210
 
21550 ripley 1211
    Rp->rhome = R_Home;
9469 ripley 1212
 
31698 ripley 1213
    Rp->home = getRUser();
9469 ripley 1214
    R_SetParams(Rp);
1215
 
1216
/*
1217
 *  Since users' expectations for save/no-save will differ, we decided
1218
 *  that they should be forced to specify in the non-interactive case.
1219
 */
38967 ripley 1220
    if (!R_Interactive && Rp->SaveAction != SA_SAVE &&
29749 ripley 1221
	Rp->SaveAction != SA_NOSAVE)
33099 ripley 1222
	R_Suicide(_("you must specify '--save', '--no-save' or '--vanilla'"));
9469 ripley 1223
 
1224
    if (InThreadReadConsole &&
45070 ripley 1225
	(!(EhiWakeUp = CreateEvent(NULL, FALSE, FALSE, NULL)) ||
9469 ripley 1226
	 (_beginthread(ReaderThread, 0, NULL) == -1)))
45070 ripley 1227
	R_Suicide(_("impossible to create 'reader thread'; you must free some system resources"));
9860 ripley 1228
 
33494 ripley 1229
    R_setupHistory();
9469 ripley 1230
    return 0;
1231
}
1232
 
42569 ripley 1233
/* only for back-compatibility: used by Rserve */
44201 ripley 1234
void setup_term_ui(void)
9469 ripley 1235
{
1236
    initapp(0, 0);
1237
    readconsolecfg();
1238
}
1239
 
44201 ripley 1240
void saveConsoleTitle(void)
12976 pd 1241
{
1242
    GetConsoleTitle(oldtitle, 512);
1243
}
72031 kalibera 1244
 
1245
 
1246
/* On Windows, the number of open files is essentially unlimited.
1247
 * This function returns 16,777,216 based on
1248
 * https://blogs.technet.microsoft.com/markrussinovich/2009/09/29/pushing-the-limits-of-windows-handles
1249
 */
1250
int R_GetFDLimit()
1251
{
1252
    long limit = 16L*1024L*1024L;
1253
    return (limit > INT_MAX) ? INT_MAX : limit;
1254
}
73545 kalibera 1255
 
1256
int R_EnsureFDLimit(int desired)
1257
{
1258
    long limit = 16L*1024L*1024L;
1259
    return (desired <= limit) ? desired : (int)limit;
1260
}
1261