The R Project SVN R

Rev

Rev 62583 | Rev 63439 | 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
62583 ripley 4
 *  Copyright (C) 1997--2013  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
18
 *  http://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,.. */
43
#include <process.h>		/* for _beginthread,... */
19096 ripley 44
#include <io.h>			/* for isatty, chdir */
47490 ripley 45
#ifdef _MSC_VER  /* for chdir */
46
# include <direct.h>
47
#endif
9469 ripley 48
#include "run.h"
49
#include "Startup.h"
19761 ripley 50
#include <stdlib.h>		/* for exit */
33088 ripley 51
 
43847 ripley 52
#include "win-nls.h"
33088 ripley 53
 
55668 ripley 54
void R_CleanTempDir(void);		/* from platform.c */
44201 ripley 55
void editorcleanall(void);                  /* from editor.c */
9469 ripley 56
 
32261 ripley 57
int Rwin_graphicsx = -25, Rwin_graphicsy = 0;
20669 ripley 58
 
42235 ripley 59
R_size_t R_max_memory = INT_MAX;
16578 ripley 60
Rboolean UseInternet2 = FALSE;
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
 
143
 
144
/*
145
 *  1) FATAL MESSAGES AT STARTUP
146
 */
147
 
43767 ripley 148
void R_Suicide(const char *s)
9469 ripley 149
{
150
    char  pp[1024];
151
 
32888 ripley 152
    snprintf(pp, 1024, _("Fatal error: %s\n"), s);
9469 ripley 153
    R_ShowMessage(pp);
154
    R_CleanUp(SA_SUICIDE, 2, 0);
155
}
156
 
157
/*
158
 *  2. CONSOLE I/O
159
 */
160
 
161
/*
162
 * We support 4 different type of input.
163
 * 1) from the gui console;
164
 * 2) from a character mode console (interactive);
165
 * 3) from a pipe under --ess, i.e, interactive.
166
 * 4) from a file or from a pipe (not interactive)
167
 *
168
 * Hence, it is better to have a different function for every
169
 * situation.
170
 * Same, it is true for output (but in this case, 2=3=4)
171
 *
172
 * BTW, 3 and 4 are different on input  since fgets,ReadFile...
173
 * "blocks" =>  (e.g.) you cannot give focus to the graphics device if
174
 * you are wating for input. For this reason, input is got in a different
175
 * thread
176
 *
177
 * All works in this way:
178
 * R_ReadConsole calls TrueReadConsole which points to:
179
 * case 1: GuiReadConsole
180
 * case 2 and 3: ThreadedReadConsole
181
 * case 4: FileReadConsole
182
 * ThreadedReadConsole wake up our 'reader thread' and wait until
183
 * a new line of input is available. The 'reader thread' uses
184
 * InThreadReadConsole to get it. InThreadReadConsole points to:
185
 * case 2: CharReadConsole
186
 * case 3: FileReadConsole
187
*/
188
 
189
/* Global variables */
43767 ripley 190
static int (*TrueReadConsole) (const char *, char *, int, int);
191
static int (*InThreadReadConsole) (const char *, char *, int, int);
192
static void (*TrueWriteConsole) (const char *, int);
193
static void (*TrueWriteConsoleEx) (const char *, int, int);
9469 ripley 194
HANDLE EhiWakeUp;
43767 ripley 195
static const char *tprompt;
196
static char *tbuf;
9469 ripley 197
static  int tlen, thist, lineavailable;
198
 
199
 /* Fill a text buffer with user typed console input. */
200
int
43767 ripley 201
R_ReadConsole(const char *prompt, unsigned char *buf, int len,
202
	      int addtohistory)
9469 ripley 203
{
204
    R_ProcessEvents();
205
    return TrueReadConsole(prompt, (char *) buf, len, addtohistory);
206
}
207
 
208
	/* Write a text buffer to the console. */
209
	/* All system output is filtered through this routine. */
210
 
43767 ripley 211
void R_WriteConsole(const char *buf, int len)
9469 ripley 212
{
213
    R_ProcessEvents();
40812 urbaneks 214
    if (TrueWriteConsole) TrueWriteConsole(buf, len);
215
    else TrueWriteConsoleEx(buf, len, 0);
9469 ripley 216
}
217
 
218
 
43767 ripley 219
void R_WriteConsoleEx(const char *buf, int len, int otype)
40812 urbaneks 220
{
221
    R_ProcessEvents();
222
    if (TrueWriteConsole) TrueWriteConsole(buf, len);
223
    else TrueWriteConsoleEx(buf, len, otype);
224
}
9469 ripley 225
 
40812 urbaneks 226
 
227
 
9469 ripley 228
/*1: from GUI console */
14670 ripley 229
int R_is_running = 0;
9469 ripley 230
 
231
void Rconsolesetwidth(int cols)
232
{
233
    if(R_is_running && setWidthOnResize)
234
	R_SetOptionWidth(cols);
235
}
236
 
237
static int
43767 ripley 238
GuiReadConsole(const char *prompt, char *buf, int len, int addtohistory)
9469 ripley 239
{
20824 ripley 240
    int res;
41883 ripley 241
    const char *NormalPrompt =
54049 ripley 242
	CHAR(STRING_ELT(GetOption1(install("prompt")), 0));
9469 ripley 243
 
244
    if(!R_is_running) {
245
	R_is_running = 1;
246
	Rconsolesetwidth(consolecols(RConsole));
247
    }
248
    ConsoleAcceptCmd = !strcmp(prompt, NormalPrompt);
20824 ripley 249
    res = consolereads(RConsole, prompt, buf, len, addtohistory);
9469 ripley 250
    ConsoleAcceptCmd = 0;
20824 ripley 251
    return !res;
9469 ripley 252
}
253
 
254
 
255
/* 2 and 3: reading in a thread */
256
 
257
 
258
/* 'Reader thread' main function */
259
static void __cdecl ReaderThread(void *unused)
260
{
45070 ripley 261
    while(1) {
262
	WaitForSingleObject(EhiWakeUp,INFINITE);
263
	tlen = InThreadReadConsole(tprompt,tbuf,tlen,thist);
264
	lineavailable = 1;
265
	PostThreadMessage(mainThreadId, 0, 0, 0);
266
    }
9469 ripley 267
}
268
 
269
static int
43767 ripley 270
ThreadedReadConsole(const char *prompt, char *buf, int len, int addtohistory)
9469 ripley 271
{
45070 ripley 272
    sighandler_t oldint,oldbreak;
273
    /*
274
     *   SIGINT/SIGBREAK when ESS is waiting for output are a real pain:
275
     *   they get processed after user hit <return>.
276
     *   The '^C\n' in raw Rterm is nice. But, do we really need it ?
277
     */
278
    oldint = signal(SIGINT, SIG_IGN);
279
    oldbreak = signal(SIGBREAK, SIG_IGN);
280
    mainThreadId = GetCurrentThreadId();
281
    lineavailable = 0;
282
    tprompt = prompt;
283
    tbuf = buf;
284
    tlen = len;
285
    thist = addtohistory;
286
    SetEvent(EhiWakeUp);
287
    while (1) {
288
	if (!peekevent()) WaitMessage();
289
	if (lineavailable) break;
290
	doevent();
45116 ripley 291
	if(R_Tcl_do) R_Tcl_do();
45070 ripley 292
    }
293
    lineavailable = 0;
294
    /* restore handler  */
45116 ripley 295
    signal(SIGINT, oldint);
296
    signal(SIGBREAK, oldbreak);
45070 ripley 297
    return tlen;
9469 ripley 298
}
299
 
300
 
301
/*2: from character console with getline (only used as InThreadReadConsole)*/
302
static int
43767 ripley 303
CharReadConsole(const char *prompt, char *buf, int len, int addtohistory)
9469 ripley 304
{
43767 ripley 305
    int res = getline(prompt, buf, len);
38967 ripley 306
    if (addtohistory) gl_histadd(buf);
307
    return !res;
9469 ripley 308
}
309
 
310
/*3: (as InThreadReadConsole) and 4: non-interactive */
32564 ripley 311
static void *cd = NULL;
312
 
9469 ripley 313
static int
43767 ripley 314
FileReadConsole(const char *prompt, char *buf, int len, int addhistory)
9469 ripley 315
{
32564 ripley 316
    int ll, err = 0;
38967 ripley 317
 
9469 ripley 318
    if (!R_Slave) {
319
	fputs(prompt, stdout);
320
	fflush(stdout);
321
    }
40340 ripley 322
    if (fgets(buf, len, ifp ? ifp : stdin) == NULL) return 0;
32564 ripley 323
    /* translate if necessary */
324
    if(strlen(R_StdinEnc) && strcmp(R_StdinEnc, "native.enc")) {
38967 ripley 325
	size_t res, inb = strlen(buf), onb = len;
52804 ripley 326
	const char *ib = buf; 
327
	char obuf[len+1], *ob = obuf;
32564 ripley 328
	if(!cd) {
329
	    cd = Riconv_open("", R_StdinEnc);
32888 ripley 330
	    if(!cd) error(_("encoding '%s' is not recognised"), R_StdinEnc);
32564 ripley 331
	}
332
	res = Riconv(cd, &ib, &inb, &ob, &onb);
333
	*ob = '\0';
38976 ripley 334
	err = (res == (size_t)(-1));
32564 ripley 335
	/* errors lead to part of the input line being ignored */
44722 ripley 336
	if(err) printf(_("<ERROR: re-encoding failure from encoding '%s'>\n"),
44113 ripley 337
		       R_StdinEnc);
41883 ripley 338
	strncpy(buf, obuf, len);
38967 ripley 339
    }
340
 
12256 pd 341
/* according to system.txt, should be terminated in \n, so check this
32564 ripley 342
   at eof or error */
41883 ripley 343
    ll = strlen(buf);
40340 ripley 344
    if ((err || feof(ifp ? ifp: stdin))
38967 ripley 345
	&& buf[ll - 1] != '\n' && ll < len) {
12256 pd 346
	buf[ll++] = '\n'; buf[ll] = '\0';
347
    }
38974 ripley 348
 
53592 ripley 349
    if (!R_Interactive && !R_Slave) {
9469 ripley 350
	fputs(buf, stdout);
53592 ripley 351
	fflush(stdout);
352
    }
9469 ripley 353
    return 1;
354
}
355
 
356
 
357
/* Rgui */
358
static void
43767 ripley 359
GuiWriteConsole(const char *buf,int len)
9469 ripley 360
{
32836 murdoch 361
    if (RConsole) consolewrites(RConsole, buf);
362
    else MessageBox(NULL, buf, "Console not found", MB_OK | MB_ICONEXCLAMATION);
9469 ripley 363
}
364
 
365
/* Rterm write */
366
static void
43767 ripley 367
TermWriteConsole(const char *buf, int len)
9469 ripley 368
{
369
    printf("%s", buf);
370
}
371
 
372
 
373
 
374
 
375
 
376
	/* Indicate that input is coming from the console */
377
 
44201 ripley 378
void R_ResetConsole(void)
9469 ripley 379
{
380
}
381
 
382
 
383
	/* Stdio support to ensure the console file buffer is flushed */
384
 
44201 ripley 385
void R_FlushConsole(void)
9469 ripley 386
{
45995 murdoch 387
    if (CharacterMode == RTerm && R_Interactive) fflush(stdout);
32836 murdoch 388
    else if (CharacterMode == RGui && RConsole) consoleflush(RConsole);
9469 ripley 389
}
390
 
391
 
392
	/* Reset stdin if the user types EOF on the console. */
393
 
44201 ripley 394
void R_ClearerrConsole(void)
9469 ripley 395
{
396
    if (CharacterMode == RTerm)  clearerr(stdin);
397
}
398
 
399
 
400
/*
401
 *  3) ACTIONS DURING (LONG) COMPUTATIONS
402
 */
403
 
38867 ripley 404
static void GuiBusy(int which)
9469 ripley 405
{
29220 ripley 406
    if (which == 1) gsetcursor(RConsole, WatchCursor);
407
    if (which == 0) gsetcursor(RConsole, ArrowCursor);
9469 ripley 408
}
409
 
38867 ripley 410
static void CharBusy(int which)
9469 ripley 411
{
412
}
413
 
414
void R_Busy(int which)
415
{
416
    my_R_Busy(which);
417
}
418
 
419
 
420
/*
421
 *  4) INITIALIZATION AND TERMINATION ACTIONS
422
 */
423
 
424
/*
425
   R_CleanUp is invoked at the end of the session to give the user the
426
   option of saving their data.
427
   If ask == SA_SAVEASK the user should be asked if possible (and this
428
   option should not occur in non-interactive use).
429
   If ask = SA_SAVE or SA_NOSAVE the decision is known.
430
   If ask = SA_DEFAULT use the SaveAction set at startup.
431
   In all these cases run .Last() unless quitting is cancelled.
432
   If ask = SA_SUICIDE, no save, no .Last, possibly other things.
433
 */
434
 
11155 ripley 435
void R_CleanUp(SA_TYPE saveact, int status, int runLast)
9469 ripley 436
{
437
    if(saveact == SA_DEFAULT) /* The normal case apart from R_Suicide */
438
	saveact = SaveAction;
439
 
440
    if(saveact == SA_SAVEASK) {
441
	if(R_Interactive) {
38485 murdoch 442
	    switch (R_YesNoCancel(G_("Save workspace image?"))) {
443
	    case YES:
444
		saveact = SA_SAVE;
445
		break;
446
	    case NO:
447
		saveact = SA_NOSAVE;
448
		break;
449
	    case CANCEL:
61956 ripley 450
		// There might be residual events with destroyed handles
451
		R_ProcessEvents();
38485 murdoch 452
		jump_to_toplevel();
453
		break;
454
 
9469 ripley 455
	    }
456
	} else saveact = SaveAction;
457
    }
458
 
459
    switch (saveact) {
460
    case SA_SAVE:
461
	if(runLast) R_dot_Last();
462
	if(R_DirtyImage) R_SaveGlobalEnv();
43882 ripley 463
	if (CharacterMode == RGui) {
33494 ripley 464
	    R_setupHistory(); /* re-read the history size and filename */
43882 ripley 465
	    wgl_savehistory(R_HistoryFile, R_HistorySize);
466
	} else if(R_Interactive && CharacterMode == RTerm) {
467
	    R_setupHistory(); /* re-read the history size and filename */
33494 ripley 468
	    gl_savehistory(R_HistoryFile, R_HistorySize);
469
	}
9469 ripley 470
	break;
471
    case SA_NOSAVE:
472
	if(runLast) R_dot_Last();
473
	break;
474
    case SA_SUICIDE:
475
    default:
476
	break;
477
    }
15884 luke 478
    R_RunExitFinalizers();
28991 murdoch 479
    editorcleanall();
9469 ripley 480
    CleanEd();
56032 ripley 481
    KillAllDevices(); /* Unix does not do this under SA_SUICIDE */
482
    AllDevicesKilled = TRUE; /* used in devWindows.c to inhibit callbacks */
55668 ripley 483
    R_CleanTempDir(); /* changes directory */
27590 murdoch 484
    if (R_Interactive && CharacterMode == RTerm)
12976 pd 485
	SetConsoleTitle(oldtitle);
9469 ripley 486
    if (R_CollectWarnings && saveact != SA_SUICIDE
56032 ripley 487
	&& CharacterMode == RTerm)   /* no point in doing this for Rgui
488
					as the console is about to close */
489
	PrintWarnings();        /* from device close and (if run) .Last */
9469 ripley 490
    app_cleanup();
32836 murdoch 491
    RConsole = NULL;
56032 ripley 492
    if(ifp) fclose(ifp);        /* input file from -f or --file= */
493
    if(ifile[0]) unlink(ifile); /* input file from -e */
9469 ripley 494
    exit(status);
495
}
496
 
497
/*
498
 *  7) PLATFORM DEPENDENT FUNCTIONS
499
 */
500
 
501
    /*
502
       This function can be used to display the named files with the
503
       given titles and overall title.  On GUI platforms we could
504
       use a read-only window to display the result.  Here we just
505
       make up a temporary file and invoke a pager on it.
506
    */
507
 
508
    /*
509
     *     nfile   = number of files
510
     *     file    = array of filenames
33099 ripley 511
     *     headers = the 'headers' args of file.show. Printed before each file.
512
     *     wtitle  = title for window: the 'title' arg of file.show
9469 ripley 513
     *     del     = flag for whether files should be deleted after use
514
     *     pager   = pager to be used.
515
     */
516
 
44016 ripley 517
 
518
extern FILE *R_wfopen(const wchar_t *filename, const wchar_t *mode);
519
extern size_t Rf_utf8towcs(wchar_t *wc, const char *s, size_t n);
520
 
43767 ripley 521
int R_ShowFiles(int nfile, const char **file, const char **headers,
522
		const char *wtitle, Rboolean del, const char *pager)
9469 ripley 523
{
524
    int   i;
525
    char  buf[1024];
526
 
527
    if (nfile > 0) {
528
	if (pager == NULL || strlen(pager) == 0)
529
	    pager = "internal";
530
	for (i = 0; i < nfile; i++) {
29215 ripley 531
	    if(!access(file[i], R_OK)) {
9469 ripley 532
		if (!strcmp(pager, "internal")) {
46842 ripley 533
		    newpager(wtitle, file[i], CE_NATIVE, headers[i], del);
9469 ripley 534
		} else if (!strcmp(pager, "console")) {
535
		    size_t len;
44016 ripley 536
		    FILE *f;
46842 ripley 537
		    f = R_fopen(file[i], "rt");
9469 ripley 538
		    if(f) {
539
			while((len = fread(buf, 1, 1023, f))) {
540
			    buf[len] = '\0';
541
			    R_WriteConsole(buf, strlen(buf));
542
			}
543
			fclose(f);
46842 ripley 544
			if (del) DeleteFile(file[i]);
51767 ripley 545
			/* add a blank line */
546
			R_WriteConsole("", 0);
9469 ripley 547
		    }
548
		    else {
45070 ripley 549
			snprintf(buf, 1024,
44796 ripley 550
				 _("cannot open file '%s': %s"),
44795 ripley 551
				 file[i], strerror(errno));
9469 ripley 552
			warning(buf);
553
		    }
554
		} else {
45070 ripley 555
		    /* Quote path if necessary */
32704 ripley 556
		    if(pager[0] != '"' && Rf_strchr(pager, ' '))
25313 ripley 557
			snprintf(buf, 1024, "\"%s\" \"%s\"", pager, file[i]);
10656 ripley 558
		    else
25313 ripley 559
			snprintf(buf, 1024, "%s \"%s\"", pager, file[i]);
52814 ripley 560
		    runcmd(buf, CE_NATIVE, 0, 1, NULL, NULL, NULL);
9469 ripley 561
		}
562
	    } else {
33297 ripley 563
		snprintf(buf, 1024,
564
			 _("file.show(): file '%s' does not exist\n"),
25313 ripley 565
			 file[i]);
9469 ripley 566
		warning(buf);
567
	    }
568
	}
569
	return 0;
570
    }
571
    return 1;
572
}
573
 
574
 
28991 murdoch 575
    /*
576
       This function can be used to open the named files in text editors, with the
29051 murdoch 577
       given titles and overall title.
578
       If the file does not exist then the editor should be opened to create a new file.
28991 murdoch 579
    */
9469 ripley 580
 
28991 murdoch 581
    /*
582
     *     nfile   = number of files
583
     *     file    = array of filenames
584
     *     editor  = editor to be used.
585
     */
586
 
44016 ripley 587
/* As from R 2.7.0 we assume file, editor are in UTF-8 */
43760 ripley 588
int R_EditFiles(int nfile, const char **file, const char **title,
589
		const char *editor)
28991 murdoch 590
{
591
    int   i;
592
    char  buf[1024];
593
 
594
    if (nfile > 0) {
595
	if (editor == NULL || strlen(editor) == 0)
596
	    editor = "internal";
597
	for (i = 0; i < nfile; i++) {
598
	    if (!strcmp(editor, "internal")) {
44016 ripley 599
		Rgui_Edit(file[i], CE_UTF8, title[i], 0);
28991 murdoch 600
	    } else {
601
		/* Quote path if necessary */
32704 ripley 602
		if (editor[0] != '"' && Rf_strchr(editor, ' '))
28991 murdoch 603
		    snprintf(buf, 1024, "\"%s\" \"%s\"", editor, file[i]);
604
		else
605
		    snprintf(buf, 1024, "%s \"%s\"", editor, file[i]);
52814 ripley 606
		runcmd(buf, CE_UTF8, 0, 1, NULL, NULL, NULL);
28991 murdoch 607
	    }
608
 
609
	}
610
	return 0;
611
    }
612
    return 1;
613
}
614
 
46842 ripley 615
#if 0
9469 ripley 616
/* Prompt the user for a file name.  Return the length of */
617
/* the name typed.  On Gui platforms, this should bring up */
618
/* a dialog box so a user can choose files that way. */
619
 
620
extern int DialogSelectFile(char *buf, int len); /* from rui.c */
621
 
622
int R_ChooseFile(int new, char *buf, int len)
623
{
44016 ripley 624
    return DialogSelectFile(buf, len);
9469 ripley 625
}
46842 ripley 626
#endif
9469 ripley 627
 
38485 murdoch 628
/* code for R_ShowMessage, R_YesNoCancel */
9469 ripley 629
 
43767 ripley 630
void (*pR_ShowMessage)(const char *s);
631
void R_ShowMessage(const char *s)
9469 ripley 632
{
633
    (*pR_ShowMessage)(s);
634
}
635
 
636
 
43767 ripley 637
static void char_message(const char *s)
9469 ripley 638
{
639
    if (!s) return;
23258 ripley 640
    if (R_Consolefile) {
641
	/* flush out standard output in case it uses R_Consolefile */
642
	if (R_Outputfile) fflush(R_Outputfile);
643
	fprintf(R_Consolefile, "%s\n", s);
644
	fflush(R_Consolefile);
645
    } else R_WriteConsole(s, strlen(s));
9469 ripley 646
}
647
 
43767 ripley 648
static int char_YesNoCancel(const char *s)
9469 ripley 649
{
650
    char  ss[128];
651
    unsigned char a[3];
652
 
62583 ripley 653
    snprintf(ss, 128, "%s [y/n/c]: ", s);
9469 ripley 654
    R_ReadConsole(ss, a, 3, 0);
655
    switch (a[0]) {
656
    case 'y':
657
    case 'Y':
658
	return YES;
659
    case 'n':
660
    case 'N':
661
	return NO;
662
    default:
663
	return CANCEL;
664
    }
665
}
666
 
667
 
668
	/*--- Initialization Code ---*/
669
 
670
static char RHome[MAX_PATH + 7];
671
static char UserRHome[MAX_PATH + 7];
51536 ripley 672
extern char *getRHOME(int), *getRUser(void); /* in rhome.c */
44201 ripley 673
void R_setStartTime(void);
9469 ripley 674
 
675
 
676
void R_SetWin32(Rstart Rp)
677
{
35898 ripley 678
    int dummy;
679
 
35904 ripley 680
    {
681
	/* Idea here is to ask about the memory block an automatic
682
	   variable is in.  VirtualQuery rounds down to the beginning
683
	   of the page, and tells us where the allocation started and
684
	   how many bytes the pages go up */
35902 ripley 685
 
35904 ripley 686
	MEMORY_BASIC_INFORMATION buf;
36969 ripley 687
	uintptr_t bottom, top;
35904 ripley 688
 
689
	VirtualQuery(&dummy, &buf, sizeof(buf));
36969 ripley 690
	bottom = (uintptr_t) buf.AllocationBase;
691
	top = (uintptr_t) buf.BaseAddress + buf.RegionSize;
35904 ripley 692
	/* printf("stackbase %lx, size %lx\n", top, top-bottom); */
693
	R_CStackStart = top;
694
	R_CStackLimit = top - bottom;
695
    }
38967 ripley 696
 
35898 ripley 697
    R_CStackDir = 1;
9469 ripley 698
    R_Home = Rp->rhome;
33040 ripley 699
    if(strlen(R_Home) >= MAX_PATH) R_Suicide("Invalid R_HOME");
62583 ripley 700
    snprintf(RHome, MAX_PATH+7, "R_HOME=%s", R_Home);
55026 ripley 701
    for (char *p = RHome; *p; p++) if (*p == '\\') *p = '/';
9469 ripley 702
    putenv(RHome);
703
    strcpy(UserRHome, "R_USER=");
704
    strcat(UserRHome, Rp->home);
705
    putenv(UserRHome);
46445 murdoch 706
 
707
    if( !getenv("HOME") ) {
708
	strcpy(UserRHome, "HOME=");
709
	strcat(UserRHome, getRUser());
710
	putenv(UserRHome);
711
    }    
9469 ripley 712
 
42059 murdoch 713
    /* Rterm and Rgui set CharacterMode during startup, then set Rp->CharacterMode
45070 ripley 714
       from it in cmdlineoptions().  Rproxy never calls cmdlineoptions, so we need the
42059 murdoch 715
       line below */
45070 ripley 716
 
42059 murdoch 717
    CharacterMode = Rp->CharacterMode;
35902 ripley 718
    switch(CharacterMode) {
9469 ripley 719
    case RGui:
720
	R_GUIType = "Rgui";
721
	break;
722
    case RTerm:
723
	R_GUIType = "RTerm";
724
	break;
725
    default:
726
	R_GUIType = "unknown";
727
    }
728
    TrueReadConsole = Rp->ReadConsole;
729
    TrueWriteConsole = Rp->WriteConsole;
40812 urbaneks 730
    TrueWriteConsoleEx = Rp->WriteConsoleEx;
9469 ripley 731
    R_CallBackHook = Rp->CallBack;
31698 ripley 732
    pR_ShowMessage = Rp->ShowMessage;
733
    R_YesNoCancel = Rp->YesNoCancel;
734
    my_R_Busy = Rp->Busy;
21550 ripley 735
    /* Process R_HOME/etc/Renviron.site, then
27590 murdoch 736
       .Renviron or ~/.Renviron, if it exists.
11533 ripley 737
       Only used here in embedded versions */
21550 ripley 738
    if(!Rp->NoRenviron) {
739
	process_site_Renviron();
15427 hornik 740
	process_user_Renviron();
21550 ripley 741
    }
37410 ripley 742
    Rwin_fpset();  /* in extra.c */
9469 ripley 743
}
744
 
745
 
746
/* Remove and process NAME=VALUE command line arguments */
747
 
43767 ripley 748
static void Putenv(const char *str)
11533 ripley 749
{
750
    char *buf;
751
    buf = (char *) malloc((strlen(str) + 1) * sizeof(char));
752
    if(!buf) R_ShowMessage("allocation failure in reading Renviron");
753
    strcpy(buf, str);
754
    putenv(buf);
45070 ripley 755
    /* no free here: storage remains in use */
11533 ripley 756
}
757
 
758
 
9469 ripley 759
static void env_command_line(int *pac, char **argv)
760
{
761
    int ac = *pac, newac = 1; /* Remember argv[0] is process name */
762
    char **av = argv;
42707 ripley 763
    Rboolean hadE = FALSE;
9469 ripley 764
 
42707 ripley 765
    /* We don't want to parse -e expressions */
9469 ripley 766
    while(--ac) {
767
	++av;
42707 ripley 768
	if(strcmp(*av, "-e") == 0) {
769
	    hadE = TRUE;
45070 ripley 770
	    argv[newac++] = *av;
42707 ripley 771
	    continue;
772
	}
773
	if(!hadE && **av != '-' && Rf_strchr(*av, '='))
9469 ripley 774
	    Putenv(*av);
775
	else
776
	    argv[newac++] = *av;
42707 ripley 777
	hadE = FALSE;
9469 ripley 778
    }
779
    *pac = newac;
780
}
781
 
27089 ripley 782
char *PrintUsage(void)
783
{
784
    static char msg[5000];
785
    char msg0[] =
52419 ripley 786
	"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 787
	msg1[] =
45070 ripley 788
	"  --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",
27590 murdoch 789
	msg2[] =
57136 ripley 790
	"  --vanilla             Combine --no-save, --no-restore, --no-site-file,\n                          --no-init-file and --no-environ\n",
27089 ripley 791
	msg2b[] =
45070 ripley 792
	"  --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 793
	msg3[] =
48853 murdoch 794
	"  -q, --quiet           Don't print startup message\n  --silent              Same as --quiet\n  --slave               Make R run as quietly as possible\n  --verbose             Print more information about progress\n  --internet2           Use Internet Explorer for proxies etc.\n  --args                Skip the rest of the command line\n",
27590 murdoch 795
	msg4[] =
46118 ripley 796
	"  --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",
797
	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 798
    if(CharacterMode == RTerm)
27089 ripley 799
	strcpy(msg, "Usage: Rterm [options] [< infile] [> outfile] [EnvVars]\n\n");
800
    else strcpy(msg, "Usage: Rgui [options] [EnvVars]\n\n");
801
    strcat(msg, msg0);
802
    strcat(msg, msg1);
803
    strcat(msg, msg2);
804
    strcat(msg, msg2b);
805
    strcat(msg, msg3);
806
    if(CharacterMode == RTerm) strcat(msg, msg4);
46118 ripley 807
    strcat(msg, msg5);
40396 ripley 808
    strcat(msg, "\n");
27089 ripley 809
    return msg;
810
}
811
 
44201 ripley 812
void R_setupHistory(void)
33494 ripley 813
{
814
    int value, ierr;
815
    char *p;
27089 ripley 816
 
33494 ripley 817
    if ((R_HistoryFile = getenv("R_HISTFILE")) == NULL)
45070 ripley 818
	R_HistoryFile = ".Rhistory";
33494 ripley 819
    R_HistorySize = 512;
820
    if ((p = getenv("R_HISTSIZE"))) {
45070 ripley 821
	value = R_Decode2Long(p, &ierr);
822
	if (ierr != 0 || value < 0)
823
	    R_ShowMessage("WARNING: invalid R_HISTSIZE ignored;");
824
	else
825
	    R_HistorySize = value;
33494 ripley 826
    }
827
}
14488 ripley 828
 
46078 ripley 829
#include <sys/stat.h>
830
static int isDir(char *path)
831
{
832
    struct stat sb;
833
    int isdir = 0;
834
    if(!path) return 0;
835
    if(stat(path, &sb) == 0) {
836
	isdir = (sb.st_mode & S_IFDIR) > 0; /* is a directory */
837
	/* We want to know if the directory is writable by this user,
838
	   which mode does not tell us */
839
	isdir &= (access(path, W_OK) == 0);
840
    }
841
    return isdir;
842
}
843
 
59833 ripley 844
extern void BindDomain(char *R_Home);
845
 
9469 ripley 846
int cmdlineoptions(int ac, char **av)
847
{
11007 ripley 848
    int   i, ierr;
20094 ripley 849
    R_size_t value;
31689 ripley 850
    char *p;
40396 ripley 851
    char  s[1024], cmdlines[10000];
42716 ripley 852
    R_size_t Virtual;
9469 ripley 853
    structRstart rstart;
854
    Rstart Rp = &rstart;
25603 ripley 855
    Rboolean usedRdata = FALSE, processing = TRUE;
9469 ripley 856
 
21550 ripley 857
    /* ensure R_Home gets set early: we are in rgui or rterm here */
51536 ripley 858
    R_Home = getRHOME(3);
33001 ripley 859
    /* need this for moduleCdynload for iconv.dll */
860
    InitFunctionHashing();
62584 ripley 861
    snprintf(RHome, MAX_PATH+7, "R_HOME=%s", R_Home);
33001 ripley 862
    putenv(RHome);
59833 ripley 863
    BindDomain(R_Home);
27590 murdoch 864
 
9469 ripley 865
    R_setStartTime();
866
 
867
    /* Store the command line arguments before they are processed
868
       by the different option handlers. We do this here so that
869
       we get all the name=value pairs. Otherwise these will
870
       have been removed by the time we get to call
871
       R_common_command_line().
45070 ripley 872
    */
29748 ripley 873
    R_set_command_line_arguments(ac, av);
9469 ripley 874
 
875
 
11168 ripley 876
    /* set defaults for R_max_memory. This is set here so that
877
       embedded applications get no limit */
45070 ripley 878
    {
42715 ripley 879
	MEMORYSTATUSEX ms;
43865 murdoch 880
	ms.dwLength = sizeof(MEMORYSTATUSEX);
42715 ripley 881
	GlobalMemoryStatusEx(&ms); /* Win2k or later */
42716 ripley 882
	Virtual = ms.ullTotalVirtual; /* uint64 = DWORDLONG */
43328 ripley 883
#ifdef WIN64
42716 ripley 884
	R_max_memory = ms.ullTotalPhys;
42715 ripley 885
#else
43328 ripley 886
	R_max_memory = min(Virtual - 512*Mega, ms.ullTotalPhys);
42715 ripley 887
#endif
27590 murdoch 888
 
43328 ripley 889
	/* need enough to start R, with some head room */
890
	R_max_memory = max(32 * Mega, R_max_memory);
891
    }
892
 
9469 ripley 893
    R_DefParams(Rp);
894
    Rp->CharacterMode = CharacterMode;
895
    for (i = 1; i < ac; i++)
896
	if (!strcmp(av[i], "--no-environ") || !strcmp(av[i], "--vanilla"))
45070 ripley 897
	    Rp->NoRenviron = TRUE;
9469 ripley 898
 
899
    Rp->CallBack = R_DoNothing;
31698 ripley 900
    /* Here so that --ess and similar can change */
9469 ripley 901
    InThreadReadConsole = NULL;
902
    if (CharacterMode == RTerm) {
23258 ripley 903
	if (isatty(0) && isatty(1)) {
10470 maechler 904
	    Rp->R_Interactive = TRUE;
9469 ripley 905
	    Rp->ReadConsole = ThreadedReadConsole;
45070 ripley 906
	    InThreadReadConsole = CharReadConsole;
9469 ripley 907
	} else {
10470 maechler 908
	    Rp->R_Interactive = FALSE;
9469 ripley 909
	    Rp->ReadConsole = FileReadConsole;
910
	}
24886 ripley 911
	/* Windows 95/98/ME have a shell that cannot redirect stderr,
912
	   so don't use that on those OSes */
913
	{
914
	    OSVERSIONINFO verinfo;
45070 ripley 915
	    verinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
24886 ripley 916
	    GetVersionEx(&verinfo);
917
	    switch(verinfo.dwPlatformId) {
918
	    case VER_PLATFORM_WIN32_WINDOWS:
919
		R_Consolefile = stdout; /* used for errors */
920
		break;
921
	    default:
922
		R_Consolefile = stderr; /* used for errors */
923
	    }
924
	}
23294 ripley 925
	R_Consolefile = stderr; /* used for errors */
9469 ripley 926
	R_Outputfile = stdout;  /* used for sink-able output */
45070 ripley 927
	Rp->WriteConsole = TermWriteConsole;
31698 ripley 928
	Rp->ShowMessage = char_message;
929
	Rp->YesNoCancel = char_YesNoCancel;
930
	Rp->Busy = CharBusy;
9469 ripley 931
    } else {
10470 maechler 932
	Rp->R_Interactive = TRUE;
9469 ripley 933
	Rp->ReadConsole = GuiReadConsole;
934
	Rp->WriteConsole = GuiWriteConsole;
43847 ripley 935
	Rp->ShowMessage = askok;
936
	Rp->YesNoCancel = askyesnocancel;
31698 ripley 937
	Rp->Busy = GuiBusy;
9469 ripley 938
    }
939
 
31698 ripley 940
    pR_ShowMessage = Rp->ShowMessage; /* used here */
9469 ripley 941
    TrueWriteConsole = Rp->WriteConsole;
45070 ripley 942
    /* Rp->WriteConsole is guaranteed to be set above,
42707 ripley 943
       so we know WriteConsoleEx is not used */
9469 ripley 944
    R_CallBackHook = Rp->CallBack;
945
 
946
    /* process environment variables
947
     * precedence:  command-line, .Renviron, inherited
948
     */
949
    if(!Rp->NoRenviron) {
21550 ripley 950
	process_site_Renviron();
15427 hornik 951
	process_user_Renviron();
10470 maechler 952
	Rp->NoRenviron = TRUE;
9469 ripley 953
    }
954
    env_command_line(&ac, av);
955
 
956
    R_common_command_line(&ac, av, Rp);
957
 
59142 ripley 958
    char *q = getenv("R_WIN_INTERNET2");
959
    if (q && q[0]) UseInternet2 = TRUE;
960
    q = getenv("R_MAX_MEM_SIZE");
961
    if (q && q[0]) {
962
	value = R_Decode2Long(q, &ierr);
963
	if(ierr || value < 32 * Mega || value > Virtual) {
62583 ripley 964
	    snprintf(s, 1024,
965
		     _("WARNING: R_MAX_MEM_SIZE value is invalid: ignored\n"));
59142 ripley 966
	    R_ShowMessage(s);
967
	} else R_max_memory = value;
968
    }
969
 
40396 ripley 970
    cmdlines[0] = '\0';
9469 ripley 971
    while (--ac) {
25603 ripley 972
	if (processing && **++av == '-') {
28410 ripley 973
	    if (!strcmp(*av, "--help") || !strcmp(*av, "-h")) {
27089 ripley 974
		R_ShowMessage(PrintUsage());
975
		exit(0);
976
	    }else if (!strcmp(*av, "--no-environ")) {
10470 maechler 977
		Rp->NoRenviron = TRUE;
9469 ripley 978
	    } else if (!strcmp(*av, "--ess")) {
979
/* Assert that we are interactive even if input is from a file */
10470 maechler 980
		Rp->R_Interactive = TRUE;
9469 ripley 981
		Rp->ReadConsole = ThreadedReadConsole;
45070 ripley 982
		InThreadReadConsole = FileReadConsole;
46005 ripley 983
		setvbuf(stdout, NULL, _IONBF, 0);
16578 ripley 984
	    } else if (!strcmp(*av, "--internet2")) {
985
		UseInternet2 = TRUE;
9469 ripley 986
	    } else if (!strcmp(*av, "--mdi")) {
987
		MDIset = 1;
988
	    } else if (!strcmp(*av, "--sdi") || !strcmp(*av, "--no-mdi")) {
989
		MDIset = -1;
11007 ripley 990
	    } else if (!strncmp(*av, "--max-mem-size", 14)) {
991
		if(strlen(*av) < 16) {
992
		    ac--; av++; p = *av;
993
		}
994
		else
995
		    p = &(*av)[15];
996
		if (p == NULL) {
32888 ripley 997
		    R_ShowMessage(_("WARNING: no max-mem-size given\n"));
11007 ripley 998
		    break;
999
		}
20094 ripley 1000
		value = R_Decode2Long(p, &ierr);
11007 ripley 1001
		if(ierr) {
1002
		    if(ierr < 0)
62583 ripley 1003
			snprintf(s, 1024,
1004
				 _("WARNING: --max-mem-size value is invalid: ignored\n"));
11007 ripley 1005
		    else
62583 ripley 1006
			snprintf(s, 1024,
1007
				 _("WARNING: --max-mem-size=%lu%c: too large and ignored\n"),
36413 ripley 1008
				(unsigned long) value,
42715 ripley 1009
				(ierr == 1) ? 'M': ((ierr == 2) ? 'K': 'G'));
11007 ripley 1010
		    R_ShowMessage(s);
37127 ripley 1011
		} else if (value < 32 * Mega) {
62583 ripley 1012
		    snprintf(s, 1024,
1013
			     _("WARNING: --max-mem-size=%4.1fM: too small and ignored\n"),
1014
			     value/(1024.0 * 1024.0));
11007 ripley 1015
		    R_ShowMessage(s);
42715 ripley 1016
		} else if (value > Virtual) {
62583 ripley 1017
		    snprintf(s, 1024,
1018
			     _("WARNING: --max-mem-size=%4.0fM: too large and taken as %uM\n"),
1019
			     value/(1024.0 * 1024.0),
1020
			     (unsigned int) (Virtual/(1024.0 * 1024.0)));
42715 ripley 1021
		    R_max_memory = Virtual;
36413 ripley 1022
		    R_ShowMessage(s);
11007 ripley 1023
		} else
1024
		    R_max_memory = value;
27590 murdoch 1025
	    } else if(!strcmp(*av, "--debug")) {
31698 ripley 1026
		DebugMenuitem = TRUE;
28138 murdoch 1027
		breaktodebugger();
25603 ripley 1028
	    } else if(!strcmp(*av, "--args")) {
1029
		break;
40340 ripley 1030
	    } else if(CharacterMode == RTerm && !strcmp(*av, "-f")) {
1031
		ac--; av++;
1032
		Rp->R_Interactive = FALSE;
1033
		Rp->ReadConsole = FileReadConsole;
40349 ripley 1034
		if(strcmp(*av, "-")) {
1035
		    ifp = R_fopen(*av, "r");
1036
		    if(!ifp) {
45070 ripley 1037
			snprintf(s, 1024,
1038
				 _("cannot open file '%s': %s"),
44795 ripley 1039
				 *av, strerror(errno));
40349 ripley 1040
			R_Suicide(s);
1041
		    }
40340 ripley 1042
		}
1043
	    } else if(CharacterMode == RTerm && !strncmp(*av, "--file=", 7)) {
1044
		Rp->R_Interactive = FALSE;
1045
		Rp->ReadConsole = FileReadConsole;
40349 ripley 1046
		if(strcmp((*av)+7, "-")) {
1047
		    ifp = R_fopen( (*av)+7, "r");
1048
		    if(!ifp) {
45070 ripley 1049
			snprintf(s, 1024,
1050
				 _("cannot open file '%s': %s"),
44795 ripley 1051
				 (*av)+7, strerror(errno));
40349 ripley 1052
			R_Suicide(s);
1053
		    }
40340 ripley 1054
		}
40396 ripley 1055
	    } else if(CharacterMode == RTerm && !strcmp(*av, "-e")) {
1056
		ac--; av++;
1057
		if(strlen(cmdlines) + strlen(*av) + 2 <= 10000) {
1058
		    strcat(cmdlines, *av);
1059
		    strcat(cmdlines, "\n");
1060
		} else {
1061
		    snprintf(s, 1024, _("WARNING: '-e %s' omitted as input is too long\n"), *av);
1062
		    R_ShowMessage(s);
45070 ripley 1063
		}
9469 ripley 1064
	    } else {
33297 ripley 1065
		snprintf(s, 1024, _("WARNING: unknown option '%s'\n"), *av);
9469 ripley 1066
		R_ShowMessage(s);
1067
	    }
1068
	} else {
46118 ripley 1069
	    /* Look for *.RData, as given by drag-and-drop 
1070
	       and file association */
44187 murdoch 1071
	    char path[MAX_PATH];
14488 ripley 1072
 
27590 murdoch 1073
	    if(!usedRdata &&
44187 murdoch 1074
	       strlen(*av) >= 6 &&
1075
	       stricmp(*av+strlen(*av)-6, ".RData") == 0) {
1076
		set_workspace_name(*av);
28888 ripley 1077
		strcpy(path, *av); /* this was generated by Windows so must fit */
14488 ripley 1078
		for (p = path; *p; p++) if (*p == '\\') *p = '/';
32704 ripley 1079
		p = Rf_strrchr(path, '/');
14488 ripley 1080
		if(p) {
1081
		    *p = '\0';
1082
		    chdir(path);
1083
		}
1084
		usedRdata = TRUE;
1085
		Rp->RestoreAction = SA_RESTORE;
1086
	    } else {
33084 ripley 1087
		snprintf(s, 1024, _("ARGUMENT '%s' __ignored__\n"), *av);
14488 ripley 1088
		R_ShowMessage(s);
1089
	    }
9469 ripley 1090
	}
1091
    }
40396 ripley 1092
    if(strlen(cmdlines)) {
1093
	if(ifp) R_Suicide(_("cannot use -e with -f or --file"));
1094
	Rp->R_Interactive = FALSE;
1095
	Rp->ReadConsole = FileReadConsole;
46078 ripley 1096
	{
1097
	    char *tm;
1098
	    tm = getenv("TMPDIR");
1099
	    if (!isDir(tm)) {
1100
		tm = getenv("TMP");
1101
		if (!isDir(tm)) {
1102
		    tm = getenv("TEMP");
1103
		    if (!isDir(tm))
1104
			tm = getenv("R_USER"); /* this one will succeed */
1105
		}
1106
	    }
53070 ripley 1107
	    /* in case getpid() is not unique -- has been seen under Windows */
62583 ripley 1108
	    snprintf(ifile, 1024, "%s/Rscript%x%x", tm, getpid(), 
1109
		     (unsigned int) GetTickCount());
46078 ripley 1110
	    ifp = fopen(ifile, "w+b");
1111
	    if(!ifp) R_Suicide(_("creation of tmpfile failed -- set TMPDIR suitably?"));
1112
	}
40396 ripley 1113
	fwrite(cmdlines, strlen(cmdlines)+1, 1, ifp);
1114
	fflush(ifp);
1115
	rewind(ifp);
1116
    }
1117
    if (ifp && Rp->SaveAction != SA_SAVE) Rp->SaveAction = SA_NOSAVE;
1118
 
21550 ripley 1119
    Rp->rhome = R_Home;
9469 ripley 1120
 
31698 ripley 1121
    Rp->home = getRUser();
9469 ripley 1122
    R_SetParams(Rp);
1123
 
1124
/*
1125
 *  Since users' expectations for save/no-save will differ, we decided
1126
 *  that they should be forced to specify in the non-interactive case.
1127
 */
38967 ripley 1128
    if (!R_Interactive && Rp->SaveAction != SA_SAVE &&
29749 ripley 1129
	Rp->SaveAction != SA_NOSAVE)
33099 ripley 1130
	R_Suicide(_("you must specify '--save', '--no-save' or '--vanilla'"));
9469 ripley 1131
 
1132
    if (InThreadReadConsole &&
45070 ripley 1133
	(!(EhiWakeUp = CreateEvent(NULL, FALSE, FALSE, NULL)) ||
9469 ripley 1134
	 (_beginthread(ReaderThread, 0, NULL) == -1)))
45070 ripley 1135
	R_Suicide(_("impossible to create 'reader thread'; you must free some system resources"));
9860 ripley 1136
 
33494 ripley 1137
    R_setupHistory();
9469 ripley 1138
    return 0;
1139
}
1140
 
42569 ripley 1141
/* only for back-compatibility: used by Rserve */
44201 ripley 1142
void setup_term_ui(void)
9469 ripley 1143
{
1144
    initapp(0, 0);
1145
    readconsolecfg();
1146
}
1147
 
44201 ripley 1148
void saveConsoleTitle(void)
12976 pd 1149
{
1150
    GetConsoleTitle(oldtitle, 512);
1151
}