The R Project SVN R

Rev

Rev 89790 | 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
87950 ripley 3
 *  Copyright (C) 1997--2025  The R Core Team
9469 ripley 4
 *  Copyright (C) 1995, 1996  Robert Gentleman and Ross Ihaka
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
19066 hornik 38
#include <windows.h>		/* for CreateEvent,.. */
83755 kalibera 39
#include <shlobj.h>		/* for SHGetKnownFolderPath */
40
#include <knownfolders.h>
19066 hornik 41
#include <process.h>		/* for _beginthread,... */
83755 kalibera 42
#include <io.h>			/* for isatty */
9469 ripley 43
#include "run.h"
44
#include "Startup.h"
19761 ripley 45
#include <stdlib.h>		/* for exit */
33088 ripley 46
 
43847 ripley 47
#include "win-nls.h"
33088 ripley 48
 
81952 kalibera 49
/* Callbacks also available under Unix */
82031 kalibera 50
static void (*ptr_Busy) (int);
51
static void (*ptr_CleanUp) (SA_TYPE, int, int);
52
static void (*ptr_ClearerrConsole) (void);
53
static void (*ptr_FlushConsole) (void);
54
static void (*ptr_ProcessEvents) (void); /* aka CallBack on Windows */
55
static int  (*ptr_ReadConsole) (const char *, unsigned char *, int, int);
56
static void (*ptr_ResetConsole) (void);
57
static void (*ptr_ShowMessage) (const char *s);
58
static void (*ptr_Suicide) (const char *s);
59
static void (*ptr_WriteConsole) (const char *, int);
60
static void (*ptr_WriteConsoleEx) (const char *, int, int);
81952 kalibera 61
 
62
/* Windows-specific callbacks */
63
static int R_YesNoCancel(const char *s);
82031 kalibera 64
static int (*ptr_YesNoCancel)(const char *s);
81952 kalibera 65
 
66
/* Default implementations of callbacks added in version 1 of structRstart */
67
static void Rstd_CleanUp(SA_TYPE saveact, int status, int runLast);
68
static void Rstd_ClearerrConsole(void);
69
static void Rstd_FlushConsole(void);
70
static void Rstd_ResetConsole(void);
71
static void Rstd_Suicide(const char *s);
72
 
55668 ripley 73
void R_CleanTempDir(void);		/* from platform.c */
44201 ripley 74
void editorcleanall(void);                  /* from editor.c */
9469 ripley 75
 
32261 ripley 76
int Rwin_graphicsx = -25, Rwin_graphicsy = 0;
20669 ripley 77
 
29749 ripley 78
extern SA_TYPE SaveAction; /* from ../main/startup.c */
31698 ripley 79
Rboolean DebugMenuitem = FALSE;  /* exported for rui.c */
40340 ripley 80
static FILE *ifp = NULL;
83755 kalibera 81
static char *ifile = NULL;
9469 ripley 82
 
84952 kalibera 83
UImode  CharacterMode = RGui; /* some compilers want initialized for export */
87950 ripley 84
int EmitEmbeddedUTF8 = FALSE;
9469 ripley 85
int ConsoleAcceptCmd;
83755 kalibera 86
Rboolean set_workspace_name(const char *fn); /* ../main/startup.c */
9469 ripley 87
 
88
/* used to avoid some flashing during cleaning up */
11067 maechler 89
Rboolean AllDevicesKilled = FALSE;
9469 ripley 90
 
12976 pd 91
static char oldtitle[512];
9469 ripley 92
 
84952 kalibera 93
Rboolean UserBreak = FALSE;
9469 ripley 94
 
95
/* callbacks */
44201 ripley 96
static void R_DoNothing(void) {}
9469 ripley 97
 
98
/*
99
 *   Called at I/O, during eval etc to process GUI events.
100
 */
101
 
84952 kalibera 102
typedef void (*DO_FUNC)(void);
45116 ripley 103
static void (* R_Tcl_do)(void) = NULL; /* Initialized to be sure */
45188 ripley 104
 
105
void set_R_Tcldo(DO_FUNC ptr)
45116 ripley 106
{
107
    if (R_Tcl_do)
108
	error("Thief about! Something other than package tcltk has set or is attempting to set R_Tcl_do");
109
    R_Tcl_do = ptr;
110
    return;
111
}
9469 ripley 112
 
45188 ripley 113
void unset_R_Tcldo(DO_FUNC ptr)
45116 ripley 114
{
115
    /* This needs to be a warning not an error, or tcltk will not be able
116
       to be detached. */
117
    if (R_Tcl_do != ptr)
118
	warning("Thief about! Something other than package tcltk has set or is attempting to unset R_Tcl_do");
119
    R_Tcl_do = NULL;
120
    return;
121
}
122
 
9469 ripley 123
void R_ProcessEvents(void)
124
{
88392 kalibera 125
    while (peekevent()) doevent();
45074 ripley 126
    if (cpuLimit > 0.0 || elapsedLimit > 0.0) {
81306 luke 127
#ifdef HAVE_CHECK_TIME_LIMITS
81952 kalibera 128
	/* switch to using R_CheckTimeLimits after testing on Windows */
81306 luke 129
	R_CheckTimeLimits();
130
#else
45074 ripley 131
	double cpu, data[5];
132
	R_getProcTime(data);
133
	cpu = data[0] + data[1];  /* children? */
134
	if (elapsedLimit > 0.0 && data[2] > elapsedLimit) {
135
	    cpuLimit = elapsedLimit = -1;
136
	    if (elapsedLimit2 > 0.0 && data[2] > elapsedLimit2) {
137
		elapsedLimit2 = -1.0;
138
		error(_("reached session elapsed time limit"));
139
	    } else
140
		error(_("reached elapsed time limit"));
141
	}
142
	if (cpuLimit > 0.0 && cpu > cpuLimit) {
143
	    cpuLimit = elapsedLimit = -1;
144
	    if (cpuLimit2 > 0.0 && cpu > cpuLimit2) {
145
		cpuLimit2 = -1.0;
146
		error(_("reached session CPU time limit"));
147
	    } else
148
		error(_("reached CPU time limit"));
149
	}
81306 luke 150
#endif
45074 ripley 151
    }
9469 ripley 152
    if (UserBreak) {
11067 maechler 153
	UserBreak = FALSE;
25197 luke 154
	onintr();
9469 ripley 155
    }
82031 kalibera 156
    ptr_ProcessEvents();
45116 ripley 157
    if(R_Tcl_do) R_Tcl_do();
9469 ripley 158
}
159
 
64106 murdoch 160
void R_WaitEvent(void)
161
{
162
    if (!peekevent()) waitevent();
163
}
9469 ripley 164
 
64106 murdoch 165
 
9469 ripley 166
/*
167
 *  1) FATAL MESSAGES AT STARTUP
168
 */
169
 
43767 ripley 170
void R_Suicide(const char *s)
9469 ripley 171
{
82031 kalibera 172
    ptr_Suicide(s); /* should not return */
81952 kalibera 173
    exit(2); 
174
}
175
 
176
static void Rstd_Suicide(const char *s)
177
{
9469 ripley 178
    char  pp[1024];
179
 
32888 ripley 180
    snprintf(pp, 1024, _("Fatal error: %s\n"), s);
9469 ripley 181
    R_ShowMessage(pp);
182
    R_CleanUp(SA_SUICIDE, 2, 0);
183
}
184
 
185
/*
186
 *  2. CONSOLE I/O
187
 */
188
 
189
/*
190
 * We support 4 different type of input.
191
 * 1) from the gui console;
192
 * 2) from a character mode console (interactive);
193
 * 3) from a pipe under --ess, i.e, interactive.
194
 * 4) from a file or from a pipe (not interactive)
195
 *
196
 * Hence, it is better to have a different function for every
197
 * situation.
198
 * Same, it is true for output (but in this case, 2=3=4)
199
 *
200
 * BTW, 3 and 4 are different on input  since fgets,ReadFile...
201
 * "blocks" =>  (e.g.) you cannot give focus to the graphics device if
202
 * you are wating for input. For this reason, input is got in a different
203
 * thread
204
 *
205
 * All works in this way:
82031 kalibera 206
 * R_ReadConsole calls ptr_ReadConsole which points to:
9469 ripley 207
 * case 1: GuiReadConsole
208
 * case 2 and 3: ThreadedReadConsole
209
 * case 4: FileReadConsole
210
 * ThreadedReadConsole wake up our 'reader thread' and wait until
211
 * a new line of input is available. The 'reader thread' uses
212
 * InThreadReadConsole to get it. InThreadReadConsole points to:
213
 * case 2: CharReadConsole
214
 * case 3: FileReadConsole
215
*/
216
 
217
/* Global variables */
81626 kalibera 218
static int (*InThreadReadConsole) (const char *, unsigned char *, int, int);
81952 kalibera 219
 
83166 kalibera 220
/* EhiWakeUp is a synchronization Event between the main thread and the reader
221
   thread. It is set by the main thread to inform the reader thread it should
222
   start reading a line.
81952 kalibera 223
 
83166 kalibera 224
   ReadMsgWindow is a message-only window used for synchronization between the
225
   main thread and the reader thread. The reader thread sends a message to the
226
   window when it needs the main thread to perform completion or when the line
227
   is available. The window procedure will set "lineavailable" or run the R
228
   code for performing completion. */
229
 
230
static HANDLE EhiWakeUp;
231
static HWND ReadMsgWindow;
232
#define WM_RREADMSG_EVENT ( WM_USER + 2 )
233
 
234
static LRESULT CALLBACK
235
ReadMsgWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
236
 
43767 ripley 237
static const char *tprompt;
81626 kalibera 238
static unsigned char *tbuf;
83166 kalibera 239
static int tlen, thist;
240
static int lineavailable;
9469 ripley 241
 
83151 kalibera 242
static int ReaderThreadTabHook(char *, int, int *);
243
static int (*InThreadTabHook)(char *, int, int *);
244
static struct {
245
    char *buf;
246
    int offset;
247
    int *loc;
248
    int result;
249
    HANDLE done;
250
} completionrequest;
251
 
9469 ripley 252
 /* Fill a text buffer with user typed console input. */
253
int
43767 ripley 254
R_ReadConsole(const char *prompt, unsigned char *buf, int len,
255
	      int addtohistory)
9469 ripley 256
{
257
    R_ProcessEvents();
89281 luke 258
    int res = ptr_ReadConsole(prompt, buf, len, addtohistory);
259
    if (R_interrupts_pending)
260
        onintrNoResume();
261
    return res;
9469 ripley 262
}
263
 
264
	/* Write a text buffer to the console. */
265
	/* All system output is filtered through this routine. */
266
 
43767 ripley 267
void R_WriteConsole(const char *buf, int len)
9469 ripley 268
{
269
    R_ProcessEvents();
82031 kalibera 270
    if (ptr_WriteConsole) ptr_WriteConsole(buf, len);
271
    else ptr_WriteConsoleEx(buf, len, 0);
9469 ripley 272
}
273
 
274
 
43767 ripley 275
void R_WriteConsoleEx(const char *buf, int len, int otype)
40812 urbaneks 276
{
277
    R_ProcessEvents();
82031 kalibera 278
    if (ptr_WriteConsole) ptr_WriteConsole(buf, len);
279
    else ptr_WriteConsoleEx(buf, len, otype);
40812 urbaneks 280
}
9469 ripley 281
 
40812 urbaneks 282
 
283
 
9469 ripley 284
/*1: from GUI console */
14670 ripley 285
int R_is_running = 0;
9469 ripley 286
 
287
void Rconsolesetwidth(int cols)
288
{
289
    if(R_is_running && setWidthOnResize)
290
	R_SetOptionWidth(cols);
291
}
292
 
293
static int
81626 kalibera 294
GuiReadConsole(const char *prompt, unsigned char *buf, int len,
295
               int addtohistory)
9469 ripley 296
{
20824 ripley 297
    int res;
85648 kalibera 298
    const void *vmax = vmaxget();
41883 ripley 299
    const char *NormalPrompt =
85648 kalibera 300
	translateChar(STRING_ELT(GetOption1(install("prompt")), 0));
9469 ripley 301
 
302
    if(!R_is_running) {
303
	R_is_running = 1;
304
	Rconsolesetwidth(consolecols(RConsole));
305
    }
306
    ConsoleAcceptCmd = !strcmp(prompt, NormalPrompt);
81626 kalibera 307
    res = consolereads(RConsole, prompt, (char *)buf, len, addtohistory);
9469 ripley 308
    ConsoleAcceptCmd = 0;
85648 kalibera 309
    vmaxset(vmax);
310
 
20824 ripley 311
    return !res;
9469 ripley 312
}
313
 
314
 
315
/* 2 and 3: reading in a thread */
316
 
83166 kalibera 317
/* runs in the main R thread */
318
static void RunCompletion(void *dummy)
319
{
320
    completionrequest.result = InThreadTabHook(
321
			completionrequest.buf,
322
			completionrequest.offset,
323
			completionrequest.loc);
324
}
325
 
326
 
327
/* runs in the main R thread */
328
static LRESULT CALLBACK
329
ReadMsgWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
330
    if (hwnd == ReadMsgWindow && uMsg == WM_RREADMSG_EVENT) {
331
	int what = (int) lParam;
332
	switch(what) {
333
	case 1:
334
	    lineavailable = 1;
335
	    return 0;
336
	case 2:
337
	    if (!R_ToplevelExec(RunCompletion, NULL))
338
		completionrequest.result = -1;
339
	    SetEvent(completionrequest.done);
340
	    return 0;
341
	}
342
    }
343
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
344
}
345
 
83151 kalibera 346
/* runs in the 'Reader thread', needs to execute the completion request
347
   on the main R thread */
348
static int ReaderThreadTabHook(char *buf, int offset, int *loc)
349
{
350
    completionrequest.buf = buf;
351
    completionrequest.offset = offset;
352
    completionrequest.loc = loc;
86822 kalibera 353
    PostMessage(ReadMsgWindow, WM_RREADMSG_EVENT, 0,
83166 kalibera 354
	       (LPARAM) 2 /* completion needed */);
83151 kalibera 355
    WaitForSingleObject(completionrequest.done, INFINITE);
356
    return completionrequest.result;
357
}
9469 ripley 358
 
359
/* 'Reader thread' main function */
360
static void __cdecl ReaderThread(void *unused)
361
{
45070 ripley 362
    while(1) {
363
	WaitForSingleObject(EhiWakeUp,INFINITE);
364
	tlen = InThreadReadConsole(tprompt,tbuf,tlen,thist);
86822 kalibera 365
	PostMessage(ReadMsgWindow, WM_RREADMSG_EVENT, 0,
83166 kalibera 366
	           (LPARAM) 1 /* line available */);
45070 ripley 367
    }
9469 ripley 368
}
369
 
83151 kalibera 370
/* runs in the main R thread */
9469 ripley 371
static int
81626 kalibera 372
ThreadedReadConsole(const char *prompt, unsigned char *buf, int len,
373
                    int addtohistory)
9469 ripley 374
{
45070 ripley 375
    sighandler_t oldint,oldbreak;
376
    /*
377
     *   SIGINT/SIGBREAK when ESS is waiting for output are a real pain:
378
     *   they get processed after user hit <return>.
379
     *   The '^C\n' in raw Rterm is nice. But, do we really need it ?
380
     */
381
    oldint = signal(SIGINT, SIG_IGN);
382
    oldbreak = signal(SIGBREAK, SIG_IGN);
383
    lineavailable = 0;
384
    tprompt = prompt;
385
    tbuf = buf;
386
    tlen = len;
387
    thist = addtohistory;
388
    SetEvent(EhiWakeUp);
389
    while (1) {
64106 murdoch 390
	R_WaitEvent();
83166 kalibera 391
	doevent();
45070 ripley 392
	if (lineavailable) break;
45116 ripley 393
	if(R_Tcl_do) R_Tcl_do();
45070 ripley 394
    }
395
    lineavailable = 0;
396
    /* restore handler  */
45116 ripley 397
    signal(SIGINT, oldint);
398
    signal(SIGBREAK, oldbreak);
45070 ripley 399
    return tlen;
9469 ripley 400
}
401
 
402
 
403
/*2: from character console with getline (only used as InThreadReadConsole)*/
404
static int
81626 kalibera 405
CharReadConsole(const char *prompt, unsigned char *buf, int len,
406
                int addtohistory)
9469 ripley 407
{
86820 kalibera 408
    /* Long lines are returned in multiple consecutive calls to
409
       CharReadConsole() */
410
    static char *line = NULL;
411
    static size_t offset = 0;
412
    static size_t remaining = 0;
413
    static int res = 0;
414
 
415
    if (!line) {
416
	res = getline2(prompt, &line);
89281 luke 417
	if (res < 0) { // ^C
418
	    R_interrupts_pending = TRUE;
419
	    gl_free(line);
420
	    line = NULL;
421
	    return 0;
422
	}
86820 kalibera 423
	if (addtohistory) gl_histadd(line);
424
	offset = 0;
425
	remaining = strlen(line); /* may be zero */
426
    }
427
 
428
    int tocopy = remaining;
429
    if (tocopy > len - 1) tocopy = len - 1;
430
 
87180 kalibera 431
    if (tocopy)
432
	memcpy(buf, line + offset, tocopy);
86820 kalibera 433
    buf[tocopy] = '\0';
434
    remaining -= tocopy;
435
    offset += tocopy;
436
 
437
    if (!remaining) {
438
	gl_free(line);
439
	line = NULL;
440
	return !res; /* return 0 on EOF */
441
    } else
442
	return 1;
9469 ripley 443
}
444
 
445
/*3: (as InThreadReadConsole) and 4: non-interactive */
32564 ripley 446
static void *cd = NULL;
447
 
9469 ripley 448
static int
81626 kalibera 449
FileReadConsole(const char *prompt, unsigned char *buf, int len, int addhistory)
9469 ripley 450
{
32564 ripley 451
    int ll, err = 0;
38967 ripley 452
 
77228 maechler 453
    if (!R_NoEcho) {
9469 ripley 454
	fputs(prompt, stdout);
455
	fflush(stdout);
456
    }
81626 kalibera 457
    if (fgets((char *)buf, len, ifp ? ifp : stdin) == NULL) return 0;
32564 ripley 458
    /* translate if necessary */
459
    if(strlen(R_StdinEnc) && strcmp(R_StdinEnc, "native.enc")) {
81626 kalibera 460
	size_t res, inb = strlen((char *)buf), onb = len;
461
	const char *ib = (char *)buf; 
52804 ripley 462
	char obuf[len+1], *ob = obuf;
32564 ripley 463
	if(!cd) {
464
	    cd = Riconv_open("", R_StdinEnc);
63439 murdoch 465
	    if(cd == (void *)-1) error(_("encoding '%s' is not recognised"), R_StdinEnc);
32564 ripley 466
	}
467
	res = Riconv(cd, &ib, &inb, &ob, &onb);
468
	*ob = '\0';
38976 ripley 469
	err = (res == (size_t)(-1));
32564 ripley 470
	/* errors lead to part of the input line being ignored */
85476 kalibera 471
	if(err) {
87222 kalibera 472
	    /* Should re-set with a stateful encoding, but some iconv
473
	       implementations forget byte-order learned from BOM. 
474
 
85476 kalibera 475
	    Riconv(cd, NULL, NULL, &ob, &onb);
476
	    *ob = '\0';
87222 kalibera 477
	    */
85476 kalibera 478
	    printf(_("<ERROR: re-encoding failure from encoding '%s'>\n"),
44113 ripley 479
		       R_StdinEnc);
85476 kalibera 480
	}
81626 kalibera 481
	strncpy((char *)buf, obuf, len);
38967 ripley 482
    }
483
 
12256 pd 484
/* according to system.txt, should be terminated in \n, so check this
32564 ripley 485
   at eof or error */
81626 kalibera 486
    ll = strlen((char *)buf);
40340 ripley 487
    if ((err || feof(ifp ? ifp: stdin))
38967 ripley 488
	&& buf[ll - 1] != '\n' && ll < len) {
12256 pd 489
	buf[ll++] = '\n'; buf[ll] = '\0';
490
    }
38974 ripley 491
 
77228 maechler 492
    if (!R_Interactive && !R_NoEcho) {
81626 kalibera 493
	fputs((char *)buf, stdout);
53592 ripley 494
	fflush(stdout);
495
    }
9469 ripley 496
    return 1;
497
}
498
 
499
 
500
/* Rgui */
501
static void
43767 ripley 502
GuiWriteConsole(const char *buf,int len)
9469 ripley 503
{
32836 murdoch 504
    if (RConsole) consolewrites(RConsole, buf);
505
    else MessageBox(NULL, buf, "Console not found", MB_OK | MB_ICONEXCLAMATION);
9469 ripley 506
}
507
 
508
/* Rterm write */
509
static void
43767 ripley 510
TermWriteConsole(const char *buf, int len)
9469 ripley 511
{
512
    printf("%s", buf);
513
}
514
 
515
 
516
 
517
 
518
 
519
	/* Indicate that input is coming from the console */
520
 
44201 ripley 521
void R_ResetConsole(void)
9469 ripley 522
{
82031 kalibera 523
    ptr_ResetConsole();
9469 ripley 524
}
525
 
81952 kalibera 526
static void Rstd_ResetConsole(void)
527
{
528
}
9469 ripley 529
 
530
	/* Stdio support to ensure the console file buffer is flushed */
531
 
44201 ripley 532
void R_FlushConsole(void)
9469 ripley 533
{
82031 kalibera 534
    ptr_FlushConsole();
81952 kalibera 535
}
536
 
537
static void Rstd_FlushConsole(void)
538
{
45995 murdoch 539
    if (CharacterMode == RTerm && R_Interactive) fflush(stdout);
32836 murdoch 540
    else if (CharacterMode == RGui && RConsole) consoleflush(RConsole);
9469 ripley 541
}
542
 
543
 
544
	/* Reset stdin if the user types EOF on the console. */
545
 
44201 ripley 546
void R_ClearerrConsole(void)
9469 ripley 547
{
82031 kalibera 548
    ptr_ClearerrConsole();
9469 ripley 549
}
550
 
81952 kalibera 551
static void Rstd_ClearerrConsole(void)
552
{
553
    if (CharacterMode == RTerm) clearerr(stdin);
554
}
9469 ripley 555
 
556
/*
557
 *  3) ACTIONS DURING (LONG) COMPUTATIONS
558
 */
559
 
38867 ripley 560
static void GuiBusy(int which)
9469 ripley 561
{
29220 ripley 562
    if (which == 1) gsetcursor(RConsole, WatchCursor);
563
    if (which == 0) gsetcursor(RConsole, ArrowCursor);
9469 ripley 564
}
565
 
38867 ripley 566
static void CharBusy(int which)
9469 ripley 567
{
568
}
569
 
570
void R_Busy(int which)
571
{
82031 kalibera 572
    ptr_Busy(which);
9469 ripley 573
}
574
 
575
 
576
/*
577
 *  4) INITIALIZATION AND TERMINATION ACTIONS
578
 */
579
 
580
/*
581
   R_CleanUp is invoked at the end of the session to give the user the
582
   option of saving their data.
583
   If ask == SA_SAVEASK the user should be asked if possible (and this
584
   option should not occur in non-interactive use).
585
   If ask = SA_SAVE or SA_NOSAVE the decision is known.
586
   If ask = SA_DEFAULT use the SaveAction set at startup.
587
   In all these cases run .Last() unless quitting is cancelled.
588
   If ask = SA_SUICIDE, no save, no .Last, possibly other things.
589
 */
590
 
11155 ripley 591
void R_CleanUp(SA_TYPE saveact, int status, int runLast)
9469 ripley 592
{
82031 kalibera 593
    ptr_CleanUp(saveact, status, runLast); /* should not return */
81952 kalibera 594
    exit(status);
595
}
596
 
597
static void Rstd_CleanUp(SA_TYPE saveact, int status, int runLast)
598
{
9469 ripley 599
    if(saveact == SA_DEFAULT) /* The normal case apart from R_Suicide */
600
	saveact = SaveAction;
601
 
602
    if(saveact == SA_SAVEASK) {
603
	if(R_Interactive) {
38485 murdoch 604
	    switch (R_YesNoCancel(G_("Save workspace image?"))) {
605
	    case YES:
606
		saveact = SA_SAVE;
607
		break;
608
	    case NO:
609
		saveact = SA_NOSAVE;
610
		break;
611
	    case CANCEL:
61956 ripley 612
		// There might be residual events with destroyed handles
613
		R_ProcessEvents();
38485 murdoch 614
		jump_to_toplevel();
615
		break;
616
 
9469 ripley 617
	    }
618
	} else saveact = SaveAction;
619
    }
620
 
621
    switch (saveact) {
622
    case SA_SAVE:
623
	if(runLast) R_dot_Last();
624
	if(R_DirtyImage) R_SaveGlobalEnv();
43882 ripley 625
	if (CharacterMode == RGui) {
33494 ripley 626
	    R_setupHistory(); /* re-read the history size and filename */
43882 ripley 627
	    wgl_savehistory(R_HistoryFile, R_HistorySize);
628
	} else if(R_Interactive && CharacterMode == RTerm) {
629
	    R_setupHistory(); /* re-read the history size and filename */
33494 ripley 630
	    gl_savehistory(R_HistoryFile, R_HistorySize);
631
	}
9469 ripley 632
	break;
633
    case SA_NOSAVE:
634
	if(runLast) R_dot_Last();
635
	break;
636
    case SA_SUICIDE:
637
    default:
638
	break;
639
    }
15884 luke 640
    R_RunExitFinalizers();
28991 murdoch 641
    editorcleanall();
9469 ripley 642
    CleanEd();
56032 ripley 643
    KillAllDevices(); /* Unix does not do this under SA_SUICIDE */
644
    AllDevicesKilled = TRUE; /* used in devWindows.c to inhibit callbacks */
55668 ripley 645
    R_CleanTempDir(); /* changes directory */
27590 murdoch 646
    if (R_Interactive && CharacterMode == RTerm)
12976 pd 647
	SetConsoleTitle(oldtitle);
9469 ripley 648
    if (R_CollectWarnings && saveact != SA_SUICIDE
56032 ripley 649
	&& CharacterMode == RTerm)   /* no point in doing this for Rgui
650
					as the console is about to close */
651
	PrintWarnings();        /* from device close and (if run) .Last */
9469 ripley 652
    app_cleanup();
32836 murdoch 653
    RConsole = NULL;
69009 ripley 654
    // Add some protection against calling this more than once:
655
    // caused by signals on Unix, so maybe cannot happen here.
656
    if(ifp) { 
657
	fclose(ifp);    /* input file from -f or --file= */
658
	ifp = NULL; 
659
    }
83755 kalibera 660
    if(ifile) {
69009 ripley 661
	unlink(ifile); /* input file from -e */
83755 kalibera 662
	free(ifile);
663
	ifile = NULL;
69009 ripley 664
    }
9469 ripley 665
    exit(status);
666
}
667
 
668
/*
669
 *  7) PLATFORM DEPENDENT FUNCTIONS
670
 */
671
 
672
    /*
673
       This function can be used to display the named files with the
674
       given titles and overall title.  On GUI platforms we could
675
       use a read-only window to display the result.  Here we just
676
       make up a temporary file and invoke a pager on it.
677
    */
678
 
679
    /*
680
     *     nfile   = number of files
681
     *     file    = array of filenames
33099 ripley 682
     *     headers = the 'headers' args of file.show. Printed before each file.
683
     *     wtitle  = title for window: the 'title' arg of file.show
9469 ripley 684
     *     del     = flag for whether files should be deleted after use
685
     *     pager   = pager to be used.
686
     */
687
 
44016 ripley 688
 
689
extern FILE *R_wfopen(const wchar_t *filename, const wchar_t *mode);
690
extern size_t Rf_utf8towcs(wchar_t *wc, const char *s, size_t n);
691
 
43767 ripley 692
int R_ShowFiles(int nfile, const char **file, const char **headers,
693
		const char *wtitle, Rboolean del, const char *pager)
9469 ripley 694
{
73584 kalibera 695
    int   i, ll;
9469 ripley 696
    char  buf[1024];
697
 
698
    if (nfile > 0) {
699
	if (pager == NULL || strlen(pager) == 0)
700
	    pager = "internal";
701
	for (i = 0; i < nfile; i++) {
29215 ripley 702
	    if(!access(file[i], R_OK)) {
9469 ripley 703
		if (!strcmp(pager, "internal")) {
46842 ripley 704
		    newpager(wtitle, file[i], CE_NATIVE, headers[i], del);
9469 ripley 705
		} else if (!strcmp(pager, "console")) {
706
		    size_t len;
44016 ripley 707
		    FILE *f;
46842 ripley 708
		    f = R_fopen(file[i], "rt");
9469 ripley 709
		    if(f) {
710
			while((len = fread(buf, 1, 1023, f))) {
711
			    buf[len] = '\0';
712
			    R_WriteConsole(buf, strlen(buf));
713
			}
714
			fclose(f);
46842 ripley 715
			if (del) DeleteFile(file[i]);
51767 ripley 716
			/* add a blank line */
717
			R_WriteConsole("", 0);
9469 ripley 718
		    }
719
		    else {
45070 ripley 720
			snprintf(buf, 1024,
44796 ripley 721
				 _("cannot open file '%s': %s"),
44795 ripley 722
				 file[i], strerror(errno));
85614 kalibera 723
			warning("%s", buf);
9469 ripley 724
		    }
725
		} else {
77926 kalibera 726
		    /* Quote path if not quoted */
727
		    if(pager[0] != '"')
25313 ripley 728
			snprintf(buf, 1024, "\"%s\" \"%s\"", pager, file[i]);
10656 ripley 729
		    else
25313 ripley 730
			snprintf(buf, 1024, "%s \"%s\"", pager, file[i]);
73584 kalibera 731
		    ll = runcmd(buf, CE_NATIVE, 0, 1, NULL, NULL, NULL);
85614 kalibera 732
		    if (ll == NOLAUNCH) warning("%s", runerror());
9469 ripley 733
		}
734
	    } else {
33297 ripley 735
		snprintf(buf, 1024,
736
			 _("file.show(): file '%s' does not exist\n"),
25313 ripley 737
			 file[i]);
85614 kalibera 738
		warning("%s", buf);
9469 ripley 739
	    }
740
	}
741
	return 0;
742
    }
743
    return 1;
744
}
745
 
746
 
28991 murdoch 747
    /*
748
       This function can be used to open the named files in text editors, with the
29051 murdoch 749
       given titles and overall title.
750
       If the file does not exist then the editor should be opened to create a new file.
28991 murdoch 751
    */
9469 ripley 752
 
28991 murdoch 753
    /*
754
     *     nfile   = number of files
755
     *     file    = array of filenames
756
     *     editor  = editor to be used.
757
     */
758
 
44016 ripley 759
/* As from R 2.7.0 we assume file, editor are in UTF-8 */
43760 ripley 760
int R_EditFiles(int nfile, const char **file, const char **title,
761
		const char *editor)
28991 murdoch 762
{
73584 kalibera 763
    int   i, ll;
28991 murdoch 764
    char  buf[1024];
765
 
766
    if (nfile > 0) {
767
	if (editor == NULL || strlen(editor) == 0)
768
	    editor = "internal";
769
	for (i = 0; i < nfile; i++) {
770
	    if (!strcmp(editor, "internal")) {
44016 ripley 771
		Rgui_Edit(file[i], CE_UTF8, title[i], 0);
28991 murdoch 772
	    } else {
77926 kalibera 773
		/* Quote path if not quoted */
774
		if (editor[0] != '"')
28991 murdoch 775
		    snprintf(buf, 1024, "\"%s\" \"%s\"", editor, file[i]);
776
		else
777
		    snprintf(buf, 1024, "%s \"%s\"", editor, file[i]);
73584 kalibera 778
		ll = runcmd(buf, CE_UTF8, 0, 1, NULL, NULL, NULL);
85614 kalibera 779
		if (ll == NOLAUNCH) warning("%s", runerror());
28991 murdoch 780
	    }
781
 
782
	}
783
	return 0;
784
    }
785
    return 1;
786
}
787
 
46842 ripley 788
#if 0
9469 ripley 789
/* Prompt the user for a file name.  Return the length of */
790
/* the name typed.  On Gui platforms, this should bring up */
791
/* a dialog box so a user can choose files that way. */
792
 
793
extern int DialogSelectFile(char *buf, int len); /* from rui.c */
794
 
795
int R_ChooseFile(int new, char *buf, int len)
796
{
44016 ripley 797
    return DialogSelectFile(buf, len);
9469 ripley 798
}
46842 ripley 799
#endif
9469 ripley 800
 
801
 
43767 ripley 802
void R_ShowMessage(const char *s)
9469 ripley 803
{
82031 kalibera 804
    ptr_ShowMessage(s);
9469 ripley 805
}
806
 
81952 kalibera 807
static int R_YesNoCancel(const char *s)
808
{
82031 kalibera 809
    return ptr_YesNoCancel(s);
81952 kalibera 810
}
9469 ripley 811
 
43767 ripley 812
static void char_message(const char *s)
9469 ripley 813
{
814
    if (!s) return;
23258 ripley 815
    if (R_Consolefile) {
816
	/* flush out standard output in case it uses R_Consolefile */
817
	if (R_Outputfile) fflush(R_Outputfile);
818
	fprintf(R_Consolefile, "%s\n", s);
819
	fflush(R_Consolefile);
820
    } else R_WriteConsole(s, strlen(s));
9469 ripley 821
}
822
 
43767 ripley 823
static int char_YesNoCancel(const char *s)
9469 ripley 824
{
825
    char  ss[128];
826
    unsigned char a[3];
827
 
62583 ripley 828
    snprintf(ss, 128, "%s [y/n/c]: ", s);
9469 ripley 829
    R_ReadConsole(ss, a, 3, 0);
830
    switch (a[0]) {
831
    case 'y':
832
    case 'Y':
833
	return YES;
834
    case 'n':
835
    case 'N':
836
	return NO;
837
    default:
838
	return CANCEL;
839
    }
840
}
841
 
842
 
843
	/*--- Initialization Code ---*/
844
 
51536 ripley 845
extern char *getRHOME(int), *getRUser(void); /* in rhome.c */
83755 kalibera 846
extern void freeRHOME(char *), freeRUser(char *);
847
extern void R_putenv_path_cpy(char *, char *, int);
44201 ripley 848
void R_setStartTime(void);
9469 ripley 849
 
81952 kalibera 850
void R_DefCallbacks(Rstart Rp, int RstartVersion)
851
{
852
    Rp->ReadConsole = NULL;
853
    Rp->WriteConsole = NULL;
854
    Rp->WriteConsoleEx = NULL;
855
    Rp->CallBack = NULL;
856
    Rp->ShowMessage = NULL;
857
    Rp->YesNoCancel = NULL;
858
    Rp->Busy = NULL;
9469 ripley 859
 
81952 kalibera 860
    if (RstartVersion > 0) {
861
	Rp->CleanUp = Rstd_CleanUp;
862
	Rp->ClearerrConsole = Rstd_ClearerrConsole;
863
	Rp->FlushConsole = Rstd_FlushConsole;
864
	Rp->ResetConsole = Rstd_ResetConsole;
865
	Rp->Suicide = Rstd_Suicide;
866
    }
867
}
868
 
9469 ripley 869
void R_SetWin32(Rstart Rp)
870
{
83460 kalibera 871
    int dummy = 0; /* -Wmaybe-uninitialized */
35898 ripley 872
 
35904 ripley 873
    {
874
	/* Idea here is to ask about the memory block an automatic
875
	   variable is in.  VirtualQuery rounds down to the beginning
876
	   of the page, and tells us where the allocation started and
877
	   how many bytes the pages go up */
35902 ripley 878
 
35904 ripley 879
	MEMORY_BASIC_INFORMATION buf;
36969 ripley 880
	uintptr_t bottom, top;
35904 ripley 881
 
882
	VirtualQuery(&dummy, &buf, sizeof(buf));
36969 ripley 883
	bottom = (uintptr_t) buf.AllocationBase;
884
	top = (uintptr_t) buf.BaseAddress + buf.RegionSize;
35904 ripley 885
	/* printf("stackbase %lx, size %lx\n", top, top-bottom); */
886
	R_CStackStart = top;
887
	R_CStackLimit = top - bottom;
72635 kalibera 888
 
889
	/* The stack detection above is not precise, in fact the stack will
890
	   not be able to grow that large. As documented, at least one page
891
	   from the space will be used as a guard page. Starting from the
892
	   top (high address), the stack is formed by committed area, the
893
	   guard page, and reserved area. The guard is used for on-demand
894
	   growing of the committed area and shrinking of the reserve.
895
	   Experiments show that the reserve would not shrink to less than
896
	   2 pages (Win7, 32bit). This is not documented and was not tested 
897
	   in other versions of Windows.*/
898
	if (R_CStackLimit > 4*4096)
899
	    R_CStackLimit -= 4*4096;
900
 
901
	/* setup_Rmainloop includes (disabled) code to test stack detection */
35904 ripley 902
    }
38967 ripley 903
 
35898 ripley 904
    R_CStackDir = 1;
83755 kalibera 905
    if(!Rp->rhome)
906
	R_Suicide("Invalid R_HOME");
907
    R_Home = (char *)malloc(strlen(Rp->rhome) + 1);
908
    if (!R_Home)
909
	R_Suicide("Allocation error");
910
    strcpy(R_Home, Rp->rhome);
911
    R_putenv_path_cpy("R_HOME", Rp->rhome, 1);
912
    R_putenv_path_cpy("R_USER", Rp->home, 0);
46445 murdoch 913
 
914
    if( !getenv("HOME") ) {
83755 kalibera 915
	char *RUser = getRUser();
916
	R_putenv_path_cpy("HOME", RUser, 0);
917
	freeRUser(RUser);
74528 kalibera 918
    }
919
    putenv("MSYS2_ENV_CONV_EXCL=R_ARCH");
9469 ripley 920
 
70086 murdoch 921
 
922
    /* This is here temporarily while the GCC version is chosen */
83755 kalibera 923
    char *gccversion = (char *)malloc(30);
924
    if (!gccversion)
925
	R_Suicide("Allocation error");
84906 kalibera 926
#ifdef __clang__
927
    snprintf(gccversion, 30, "R_COMPILED_BY=clang %d.%d.%d", __clang_major__, __clang_minor__, __clang_patchlevel__);
928
#else
70086 murdoch 929
    snprintf(gccversion, 30, "R_COMPILED_BY=gcc %d.%d.%d", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__);
84906 kalibera 930
#endif
70086 murdoch 931
    putenv(gccversion);
83755 kalibera 932
    /* no free here: storage remains in use */
70086 murdoch 933
 
42059 murdoch 934
    /* Rterm and Rgui set CharacterMode during startup, then set Rp->CharacterMode
45070 ripley 935
       from it in cmdlineoptions().  Rproxy never calls cmdlineoptions, so we need the
42059 murdoch 936
       line below */
45070 ripley 937
 
42059 murdoch 938
    CharacterMode = Rp->CharacterMode;
81952 kalibera 939
 
940
    /* Be careful when relying on Rp->EmitEmbeddedUTF8 due to potential
941
       embedding applications using old structRstart. */
35902 ripley 942
    switch(CharacterMode) {
9469 ripley 943
    case RGui:
944
	R_GUIType = "Rgui";
81952 kalibera 945
	EmitEmbeddedUTF8 = TRUE;
9469 ripley 946
	break;
947
    case RTerm:
948
	R_GUIType = "RTerm";
81952 kalibera 949
	EmitEmbeddedUTF8 = FALSE;
9469 ripley 950
	break;
951
    default:
952
	R_GUIType = "unknown";
81952 kalibera 953
	EmitEmbeddedUTF8 = (GetACP() != 65001) &&
954
	                   (Rp->EmitEmbeddedUTF8 == TRUE);
9469 ripley 955
    }
81952 kalibera 956
 
82031 kalibera 957
    ptr_CleanUp = Rstd_CleanUp;
958
    ptr_ClearerrConsole = Rstd_ClearerrConsole;
959
    ptr_FlushConsole = Rstd_FlushConsole;
960
    ptr_ResetConsole = Rstd_ResetConsole;
961
    ptr_Suicide = Rstd_Suicide;
81952 kalibera 962
 
963
    if (Rp->RstartVersion == 1) {
82031 kalibera 964
	ptr_CleanUp = Rp->CleanUp;
965
	ptr_ClearerrConsole = Rp->ClearerrConsole;
966
	ptr_FlushConsole = Rp->FlushConsole;
967
	ptr_ResetConsole = Rp->ResetConsole;
968
	ptr_Suicide = Rp->Suicide;
81952 kalibera 969
    }
970
 
77769 kalibera 971
    EmitEmbeddedUTF8 = Rp->EmitEmbeddedUTF8;
82031 kalibera 972
    ptr_ReadConsole = Rp->ReadConsole;
973
    ptr_WriteConsole = Rp->WriteConsole;
974
    ptr_WriteConsoleEx = Rp->WriteConsoleEx;
975
    ptr_ProcessEvents = Rp->CallBack;
976
    ptr_ShowMessage = Rp->ShowMessage;
977
    ptr_YesNoCancel = Rp->YesNoCancel;
978
    ptr_Busy = Rp->Busy;
21550 ripley 979
    /* Process R_HOME/etc/Renviron.site, then
27590 murdoch 980
       .Renviron or ~/.Renviron, if it exists.
11533 ripley 981
       Only used here in embedded versions */
21550 ripley 982
    if(!Rp->NoRenviron) {
983
	process_site_Renviron();
15427 hornik 984
	process_user_Renviron();
21550 ripley 985
    }
37410 ripley 986
    Rwin_fpset();  /* in extra.c */
9469 ripley 987
}
988
 
989
 
990
/* Remove and process NAME=VALUE command line arguments */
991
 
43767 ripley 992
static void Putenv(const char *str)
11533 ripley 993
{
994
    char *buf;
995
    buf = (char *) malloc((strlen(str) + 1) * sizeof(char));
996
    if(!buf) R_ShowMessage("allocation failure in reading Renviron");
997
    strcpy(buf, str);
998
    putenv(buf);
45070 ripley 999
    /* no free here: storage remains in use */
11533 ripley 1000
}
1001
 
1002
 
9469 ripley 1003
static void env_command_line(int *pac, char **argv)
1004
{
1005
    int ac = *pac, newac = 1; /* Remember argv[0] is process name */
1006
    char **av = argv;
42707 ripley 1007
    Rboolean hadE = FALSE;
9469 ripley 1008
 
42707 ripley 1009
    /* We don't want to parse -e expressions */
9469 ripley 1010
    while(--ac) {
1011
	++av;
42707 ripley 1012
	if(strcmp(*av, "-e") == 0) {
1013
	    hadE = TRUE;
45070 ripley 1014
	    argv[newac++] = *av;
42707 ripley 1015
	    continue;
1016
	}
1017
	if(!hadE && **av != '-' && Rf_strchr(*av, '='))
9469 ripley 1018
	    Putenv(*av);
1019
	else
1020
	    argv[newac++] = *av;
42707 ripley 1021
	hadE = FALSE;
9469 ripley 1022
    }
1023
    *pac = newac;
1024
}
1025
 
27089 ripley 1026
char *PrintUsage(void)
1027
{
1028
    static char msg[5000];
1029
    char msg0[] =
52419 ripley 1030
	"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 1031
	msg1[] =
77363 kalibera 1032
	"  --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 1033
	msg2[] =
57136 ripley 1034
	"  --vanilla             Combine --no-save, --no-restore, --no-site-file,\n                          --no-init-file and --no-environ\n",
27089 ripley 1035
	msg2b[] =
80832 kalibera 1036
	"  --max-ppsize=N        Set max size of protect stack to N\n",
84466 ripley 1037
	msg2c[] =
88370 smeyer 1038
	"  --max-connections=N   Set max number of connections to N\n",
27089 ripley 1039
	msg3[] =
88370 smeyer 1040
	"  -q, --quiet           Don't print startup message\n  --silent              Same as --quiet\n  -s, --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 1041
	msg4[] =
46118 ripley 1042
	"  --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",
1043
	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 1044
    if(CharacterMode == RTerm)
79996 kalibera 1045
	strcpy(msg, "Usage: Rterm [options] [EnvVars]\n\n");
27089 ripley 1046
    else strcpy(msg, "Usage: Rgui [options] [EnvVars]\n\n");
1047
    strcat(msg, msg0);
1048
    strcat(msg, msg1);
1049
    strcat(msg, msg2);
1050
    strcat(msg, msg2b);
84466 ripley 1051
    strcat(msg, msg2c);
27089 ripley 1052
    strcat(msg, msg3);
1053
    if(CharacterMode == RTerm) strcat(msg, msg4);
46118 ripley 1054
    strcat(msg, msg5);
40396 ripley 1055
    strcat(msg, "\n");
27089 ripley 1056
    return msg;
1057
}
1058
 
44201 ripley 1059
void R_setupHistory(void)
33494 ripley 1060
{
1061
    int value, ierr;
1062
    char *p;
27089 ripley 1063
 
33494 ripley 1064
    if ((R_HistoryFile = getenv("R_HISTFILE")) == NULL)
45070 ripley 1065
	R_HistoryFile = ".Rhistory";
33494 ripley 1066
    R_HistorySize = 512;
1067
    if ((p = getenv("R_HISTSIZE"))) {
45070 ripley 1068
	value = R_Decode2Long(p, &ierr);
1069
	if (ierr != 0 || value < 0)
1070
	    R_ShowMessage("WARNING: invalid R_HISTSIZE ignored;");
1071
	else
1072
	    R_HistorySize = value;
33494 ripley 1073
    }
1074
}
14488 ripley 1075
 
79342 kalibera 1076
extern int R_isWriteableDir(char *path);
46078 ripley 1077
 
77363 kalibera 1078
static Rboolean use_workspace(Rstart Rp, char *name, Rboolean usedRdata)
1079
{
1080
    char s[1024];
83755 kalibera 1081
    char *path, *p;
77363 kalibera 1082
 
1083
    if(!usedRdata) {
83755 kalibera 1084
	if (!set_workspace_name(name)) {
1085
	    snprintf(s, 1024, _("Not enough memory"));
77363 kalibera 1086
	    R_ShowMessage(s);
1087
	} else {
83755 kalibera 1088
	    path = (char *)malloc(strlen(name) + 1);	
77363 kalibera 1089
	    strcpy(path, name);
1090
	    for (p = path; *p; p++) if (*p == '\\') *p = '/';
1091
	    p = Rf_strrchr(path, '/');
1092
	    if(p) {
1093
		*p = '\0';
83755 kalibera 1094
		SetCurrentDirectory(path);
77363 kalibera 1095
	    }
1096
	    usedRdata = TRUE;
1097
	    Rp->RestoreAction = SA_RESTORE;
1098
	    return TRUE;
1099
	}
1100
    } else {
1101
	snprintf(s, 1024, _("ARGUMENT '%s' __ignored__\n"), name);
1102
	R_ShowMessage(s);
1103
    }
1104
    return FALSE;
1105
}
1106
 
9469 ripley 1107
int cmdlineoptions(int ac, char **av)
1108
{
80832 kalibera 1109
    int   i;
83755 kalibera 1110
    char  s[1024], cmdlines[10000], *RUser, *RHome;
9469 ripley 1111
    structRstart rstart;
1112
    Rstart Rp = &rstart;
25603 ripley 1113
    Rboolean usedRdata = FALSE, processing = TRUE;
9469 ripley 1114
 
21550 ripley 1115
    /* ensure R_Home gets set early: we are in rgui or rterm here */
84987 kalibera 1116
    int dirstrip = 2;
1117
#ifdef R_ARCH
1118
    if (strlen(R_ARCH) > 0)
1119
	dirstrip++;
1120
#endif 
1121
    RHome = getRHOME(dirstrip);
83755 kalibera 1122
    if(!RHome)
1123
	R_Suicide("Invalid R_HOME");
1124
    R_Home = RHome;
33001 ripley 1125
    /* need this for moduleCdynload for iconv.dll */
1126
    InitFunctionHashing();
83755 kalibera 1127
    R_putenv_path_cpy("R_HOME", RHome, 1);
1128
    BindDomain(RHome);
27590 murdoch 1129
 
9469 ripley 1130
    R_setStartTime();
1131
 
1132
    /* Store the command line arguments before they are processed
1133
       by the different option handlers. We do this here so that
1134
       we get all the name=value pairs. Otherwise these will
1135
       have been removed by the time we get to call
1136
       R_common_command_line().
45070 ripley 1137
    */
29748 ripley 1138
    R_set_command_line_arguments(ac, av);
9469 ripley 1139
 
81952 kalibera 1140
    R_DefParamsEx(Rp, RSTART_VERSION);
9469 ripley 1141
    Rp->CharacterMode = CharacterMode;
1142
    for (i = 1; i < ac; i++)
1143
	if (!strcmp(av[i], "--no-environ") || !strcmp(av[i], "--vanilla"))
45070 ripley 1144
	    Rp->NoRenviron = TRUE;
74844 kalibera 1145
	else if (!strcmp(av[i], "--cd-to-userdocs")) {
1146
	    /* This is used in shortcuts created by the installer. Previously, the
1147
	       installer resolved the user documents folder at installation time,
1148
	       but that is not good for installation under SCCM/system context where
1149
	       it resolved to documents folder in systemprofile. This has do be done
1150
	       before process_user_Renviron(), because user .Renviron may be read from
1151
	       the current directory, which is expected to be userdocs. */
83755 kalibera 1152
	    wchar_t *mydocs;
1153
	    if (SHGetKnownFolderPath(&FOLDERID_Documents, KF_FLAG_CREATE, NULL,
1154
	                             &mydocs) == S_OK)
77605 kalibera 1155
		SetCurrentDirectoryW(mydocs);
83755 kalibera 1156
	    CoTaskMemFree(mydocs);
74844 kalibera 1157
	}
9469 ripley 1158
 
1159
    Rp->CallBack = R_DoNothing;
31698 ripley 1160
    /* Here so that --ess and similar can change */
9469 ripley 1161
    InThreadReadConsole = NULL;
1162
    if (CharacterMode == RTerm) {
23258 ripley 1163
	if (isatty(0) && isatty(1)) {
10470 maechler 1164
	    Rp->R_Interactive = TRUE;
9469 ripley 1165
	    Rp->ReadConsole = ThreadedReadConsole;
45070 ripley 1166
	    InThreadReadConsole = CharReadConsole;
76905 kalibera 1167
	} else if (R_is_redirection_tty(0) && R_is_redirection_tty(1)) {
76988 kalibera 1168
	    /* Note it is not currently possible to use line editing with Msys2
1169
	       terminals such as mintty, because we cannot disable buffering in
1170
	       the terminal. One can only do that from applications linked
1171
	       against the Cygwin runtime, but R is linked against Msvcrt
76998 kalibera 1172
	       via Mingw and using multiple runtimes is not possible.
1173
 
1174
	       Msys2/cygwin is handled in AppMain() by re-executing using
1175
	       winpty. This branch is taken when winpty is not available.
1176
	    */
76905 kalibera 1177
	    Rp->R_Interactive = TRUE;
1178
	    Rp->ReadConsole = ThreadedReadConsole;
1179
	    InThreadReadConsole = FileReadConsole;
1180
	    setvbuf(stdout, NULL, _IONBF, 0);
9469 ripley 1181
	} else {
10470 maechler 1182
	    Rp->R_Interactive = FALSE;
9469 ripley 1183
	    Rp->ReadConsole = FileReadConsole;
1184
	}
24886 ripley 1185
	/* Windows 95/98/ME have a shell that cannot redirect stderr,
1186
	   so don't use that on those OSes */
1187
	{
1188
	    OSVERSIONINFO verinfo;
45070 ripley 1189
	    verinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
24886 ripley 1190
	    GetVersionEx(&verinfo);
1191
	    switch(verinfo.dwPlatformId) {
1192
	    case VER_PLATFORM_WIN32_WINDOWS:
1193
		R_Consolefile = stdout; /* used for errors */
1194
		break;
1195
	    default:
1196
		R_Consolefile = stderr; /* used for errors */
1197
	    }
1198
	}
23294 ripley 1199
	R_Consolefile = stderr; /* used for errors */
9469 ripley 1200
	R_Outputfile = stdout;  /* used for sink-able output */
45070 ripley 1201
	Rp->WriteConsole = TermWriteConsole;
31698 ripley 1202
	Rp->ShowMessage = char_message;
1203
	Rp->YesNoCancel = char_YesNoCancel;
1204
	Rp->Busy = CharBusy;
9469 ripley 1205
    } else {
10470 maechler 1206
	Rp->R_Interactive = TRUE;
9469 ripley 1207
	Rp->ReadConsole = GuiReadConsole;
1208
	Rp->WriteConsole = GuiWriteConsole;
43847 ripley 1209
	Rp->ShowMessage = askok;
1210
	Rp->YesNoCancel = askyesnocancel;
31698 ripley 1211
	Rp->Busy = GuiBusy;
9469 ripley 1212
    }
1213
 
82031 kalibera 1214
    ptr_ShowMessage = Rp->ShowMessage; /* used here */
1215
    ptr_WriteConsole = Rp->WriteConsole;
45070 ripley 1216
    /* Rp->WriteConsole is guaranteed to be set above,
42707 ripley 1217
       so we know WriteConsoleEx is not used */
82031 kalibera 1218
    ptr_ProcessEvents = Rp->CallBack;
9469 ripley 1219
 
1220
    /* process environment variables
1221
     * precedence:  command-line, .Renviron, inherited
1222
     */
1223
    if(!Rp->NoRenviron) {
21550 ripley 1224
	process_site_Renviron();
15427 hornik 1225
	process_user_Renviron();
10470 maechler 1226
	Rp->NoRenviron = TRUE;
74905 luke 1227
 
1228
	/* allow for R_MAX_[VN]SIZE and R_[VN]SIZE in user/site Renviron */
1229
	R_SizeFromEnv(Rp);
9469 ripley 1230
    }
1231
    env_command_line(&ac, av);
1232
 
1233
    R_common_command_line(&ac, av, Rp);
1234
 
40396 ripley 1235
    cmdlines[0] = '\0';
9469 ripley 1236
    while (--ac) {
25603 ripley 1237
	if (processing && **++av == '-') {
28410 ripley 1238
	    if (!strcmp(*av, "--help") || !strcmp(*av, "-h")) {
27089 ripley 1239
		R_ShowMessage(PrintUsage());
83755 kalibera 1240
		freeRHOME(RHome);
27089 ripley 1241
		exit(0);
73683 kalibera 1242
	    } else if (!strcmp(*av, "--cd-to-userdocs")) {
74844 kalibera 1243
		/* handled above before processing Renviron */
73683 kalibera 1244
	    } else if (!strcmp(*av, "--no-environ")) {
10470 maechler 1245
		Rp->NoRenviron = TRUE;
9469 ripley 1246
	    } else if (!strcmp(*av, "--ess")) {
1247
/* Assert that we are interactive even if input is from a file */
10470 maechler 1248
		Rp->R_Interactive = TRUE;
9469 ripley 1249
		Rp->ReadConsole = ThreadedReadConsole;
45070 ripley 1250
		InThreadReadConsole = FileReadConsole;
46005 ripley 1251
		setvbuf(stdout, NULL, _IONBF, 0);
16578 ripley 1252
	    } else if (!strcmp(*av, "--internet2")) {
68982 ripley 1253
/*	        This is now the default */
9469 ripley 1254
	    } else if (!strcmp(*av, "--mdi")) {
1255
		MDIset = 1;
1256
	    } else if (!strcmp(*av, "--sdi") || !strcmp(*av, "--no-mdi")) {
1257
		MDIset = -1;
27590 murdoch 1258
	    } else if(!strcmp(*av, "--debug")) {
31698 ripley 1259
		DebugMenuitem = TRUE;
28138 murdoch 1260
		breaktodebugger();
25603 ripley 1261
	    } else if(!strcmp(*av, "--args")) {
1262
		break;
40340 ripley 1263
	    } else if(CharacterMode == RTerm && !strcmp(*av, "-f")) {
1264
		ac--; av++;
63437 murdoch 1265
		if (!ac) {
1266
		    snprintf(s, 1024,
1267
			    _("option '%s' requires an argument"),
1268
			    "-f");
1269
		    R_Suicide(s);
1270
		}
40340 ripley 1271
		Rp->R_Interactive = FALSE;
1272
		Rp->ReadConsole = FileReadConsole;
40349 ripley 1273
		if(strcmp(*av, "-")) {
1274
		    ifp = R_fopen(*av, "r");
1275
		    if(!ifp) {
45070 ripley 1276
			snprintf(s, 1024,
1277
				 _("cannot open file '%s': %s"),
44795 ripley 1278
				 *av, strerror(errno));
40349 ripley 1279
			R_Suicide(s);
1280
		    }
40340 ripley 1281
		}
1282
	    } else if(CharacterMode == RTerm && !strncmp(*av, "--file=", 7)) {
1283
		Rp->R_Interactive = FALSE;
1284
		Rp->ReadConsole = FileReadConsole;
40349 ripley 1285
		if(strcmp((*av)+7, "-")) {
1286
		    ifp = R_fopen( (*av)+7, "r");
1287
		    if(!ifp) {
45070 ripley 1288
			snprintf(s, 1024,
1289
				 _("cannot open file '%s': %s"),
44795 ripley 1290
				 (*av)+7, strerror(errno));
40349 ripley 1291
			R_Suicide(s);
1292
		    }
40340 ripley 1293
		}
77363 kalibera 1294
	    } else if (!strncmp(*av, "--workspace=", 12)) {
1295
		usedRdata = use_workspace(Rp, *av + 12, usedRdata);
40396 ripley 1296
	    } else if(CharacterMode == RTerm && !strcmp(*av, "-e")) {
1297
		ac--; av++;
63514 ripley 1298
		if (!ac || !strlen(*av)) {
63437 murdoch 1299
		    snprintf(s, 1024,
63514 ripley 1300
			    _("option '%s' requires a non-empty argument"),
63437 murdoch 1301
			    "-e");
1302
		    R_Suicide(s);
1303
		}
40396 ripley 1304
		if(strlen(cmdlines) + strlen(*av) + 2 <= 10000) {
1305
		    strcat(cmdlines, *av);
1306
		    strcat(cmdlines, "\n");
1307
		} else {
1308
		    snprintf(s, 1024, _("WARNING: '-e %s' omitted as input is too long\n"), *av);
1309
		    R_ShowMessage(s);
45070 ripley 1310
		}
9469 ripley 1311
	    } else {
33297 ripley 1312
		snprintf(s, 1024, _("WARNING: unknown option '%s'\n"), *av);
9469 ripley 1313
		R_ShowMessage(s);
1314
	    }
1315
	} else {
46118 ripley 1316
	    /* Look for *.RData, as given by drag-and-drop 
1317
	       and file association */
14488 ripley 1318
 
77363 kalibera 1319
	    if (strlen(*av) >= 6 && stricmp(*av+strlen(*av)-6, ".RData") == 0)
1320
		usedRdata = use_workspace(Rp, *av, usedRdata);
9469 ripley 1321
	}
1322
    }
83755 kalibera 1323
    RUser = getRUser();
40396 ripley 1324
    if(strlen(cmdlines)) {
1325
	if(ifp) R_Suicide(_("cannot use -e with -f or --file"));
1326
	Rp->R_Interactive = FALSE;
1327
	Rp->ReadConsole = FileReadConsole;
46078 ripley 1328
	{
1329
	    char *tm;
1330
	    tm = getenv("TMPDIR");
79342 kalibera 1331
	    if (!R_isWriteableDir(tm)) {
46078 ripley 1332
		tm = getenv("TMP");
79342 kalibera 1333
		if (!R_isWriteableDir(tm)) {
46078 ripley 1334
		    tm = getenv("TEMP");
83755 kalibera 1335
		    if (!R_isWriteableDir(tm)) 
1336
			tm = RUser;
46078 ripley 1337
		}
1338
	    }
53070 ripley 1339
	    /* in case getpid() is not unique -- has been seen under Windows */
83755 kalibera 1340
	    size_t needed;
1341
	    needed = snprintf(NULL, 0, "%s/Rscript%x%x", tm, getpid(), 
1342
		              (unsigned int) GetTickCount()) + 1;
1343
	    ifile = (char *)malloc(needed);
1344
	    if (ifile) {
1345
		snprintf(ifile, needed, "%s/Rscript%x%x", tm, getpid(), 
1346
			 (unsigned int) GetTickCount());
1347
		ifp = fopen(ifile, "w+b");
1348
	    }
46078 ripley 1349
	    if(!ifp) R_Suicide(_("creation of tmpfile failed -- set TMPDIR suitably?"));
80556 kalibera 1350
	    /* Unix does unlink(ifile) here, but Windows cannot delete open files */
46078 ripley 1351
	}
86570 kalibera 1352
	if (fwrite(cmdlines, 1, strlen(cmdlines), ifp) != strlen(cmdlines))
1353
	    R_Suicide("fwrite error in cmdlineoptions");
40396 ripley 1354
	fflush(ifp);
1355
	rewind(ifp);
1356
    }
1357
    if (ifp && Rp->SaveAction != SA_SAVE) Rp->SaveAction = SA_NOSAVE;
1358
 
83755 kalibera 1359
    Rp->rhome = RHome;
1360
    Rp->home = RUser;
1361
    R_SetParams(Rp); /* will re-set R_Home to a copy */
1362
    freeRUser(RUser);
1363
    /* Do not free RHome in case some code running before R_SetParams()
1364
       captured it via global variable R_Home
1365
 
1366
       freeRHOME(RHome);
1367
    */
9469 ripley 1368
 
1369
/*
1370
 *  Since users' expectations for save/no-save will differ, we decided
1371
 *  that they should be forced to specify in the non-interactive case.
1372
 */
38967 ripley 1373
    if (!R_Interactive && Rp->SaveAction != SA_SAVE &&
29749 ripley 1374
	Rp->SaveAction != SA_NOSAVE)
33099 ripley 1375
	R_Suicide(_("you must specify '--save', '--no-save' or '--vanilla'"));
9469 ripley 1376
 
83151 kalibera 1377
    if (InThreadReadConsole) {
1378
	Rboolean ok = TRUE;
1379
	if (InThreadReadConsole == CharReadConsole) {
1380
	    /* Need to arrange for the getline completion tab hook to execute
1381
	       on the main R thread. Executing it in another thread can cause
1382
	       crashes due to at least stack overflow checking (part of the
1383
	       completion is implemented in R). */
9860 ripley 1384
 
83151 kalibera 1385
	    InThreadTabHook = gl_tab_hook;
1386
	    gl_tab_hook = ReaderThreadTabHook;
1387
	    completionrequest.done = CreateEvent(NULL, FALSE, FALSE, NULL);
1388
	    if (!completionrequest.done)
1389
		ok = FALSE;
1390
	}
83166 kalibera 1391
	if (ok) {
1392
	    HINSTANCE instance = GetModuleHandle(NULL);
1393
	    WNDCLASS wndclass = { 0, ReadMsgWindowProc, 0, 0, instance, NULL,
1394
	                          0, 0, NULL, "RReadMsg" };
1395
	    ReadMsgWindow = NULL;
1396
	    if (RegisterClass(&wndclass)) {
1397
		ReadMsgWindow = CreateWindow("RReadMsg", "RReadMsg", 0, 1, 1,
1398
		                             1, 1, HWND_MESSAGE, NULL, instance,
1399
		                             NULL);
1400
	    }
1401
	    if (!ReadMsgWindow)
1402
		ok = FALSE;
1403
	}
83151 kalibera 1404
	if (!ok || !(EhiWakeUp = CreateEvent(NULL, FALSE, FALSE, NULL)) ||
1405
	    (_beginthread(ReaderThread, 0, NULL) == -1))
1406
 
1407
	    R_Suicide(_("impossible to create 'reader thread'; you must free some system resources"));
1408
    }
33494 ripley 1409
    R_setupHistory();
9469 ripley 1410
    return 0;
1411
}
1412
 
42569 ripley 1413
/* only for back-compatibility: used by Rserve */
44201 ripley 1414
void setup_term_ui(void)
9469 ripley 1415
{
1416
    initapp(0, 0);
1417
    readconsolecfg();
1418
}
1419
 
44201 ripley 1420
void saveConsoleTitle(void)
12976 pd 1421
{
1422
    GetConsoleTitle(oldtitle, 512);
1423
}
72031 kalibera 1424
 
1425
 
1426
/* On Windows, the number of open files is essentially unlimited.
1427
 * This function returns 16,777,216 based on
1428
 * https://blogs.technet.microsoft.com/markrussinovich/2009/09/29/pushing-the-limits-of-windows-handles
1429
 */
84952 kalibera 1430
int R_GetFDLimit(void)
72031 kalibera 1431
{
1432
    long limit = 16L*1024L*1024L;
1433
    return (limit > INT_MAX) ? INT_MAX : limit;
1434
}
73545 kalibera 1435
 
1436
int R_EnsureFDLimit(int desired)
1437
{
1438
    long limit = 16L*1024L*1024L;
1439
    return (desired <= limit) ? desired : (int)limit;
1440
}
1441