Coverage Report

Created: 2026-10-28 06:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/r-source/src/main/main.c
Line
Count
Source
1
/*
2
 *  R : A Computer Language for Statistical Data Analysis
3
 *  Copyright (C) 1998-2026   The R Core Team
4
 *  Copyright (C) 2002-2005  The R Foundation
5
 *  Copyright (C) 1995, 1996  Robert Gentleman and Ross Ihaka
6
 *
7
 *  This program is free software; you can redistribute it and/or modify
8
 *  it under the terms of the GNU General Public License as published by
9
 *  the Free Software Foundation; either version 2 of the License, or
10
 *  (at your option) any later version.
11
 *
12
 *  This program is distributed in the hope that it will be useful,
13
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 *  GNU General Public License for more details.
16
 *
17
 *  You should have received a copy of the GNU General Public License
18
 *  along with this program; if not, a copy is available at
19
 *  https://www.R-project.org/Licenses/
20
 */
21
22
#ifdef HAVE_CONFIG_H
23
#include <config.h>
24
#endif
25
26
#include <math.h> /* avoid redefinition of extern in Defn.h */
27
#include <float.h>
28
#include <ctype.h>
29
#include <stdlib.h>
30
#include <string.h>
31
32
#define __MAIN__
33
#define R_USE_SIGNALS 1
34
#include <Defn.h>
35
#include <Internal.h>
36
#include "Rinterface.h"
37
#include "IOStuff.h"
38
#include "Fileio.h"
39
#include "Parse.h"
40
#include "Startup.h"
41
42
#include <locale.h>
43
#include <R_ext/Print.h>
44
45
#ifdef ENABLE_NLS
46
attribute_hidden void nl_Rdummy(void)
47
0
{
48
    /* force this in as packages use it */
49
0
    dgettext("R", "dummy - do not translate");
50
0
}
51
#endif
52
53
54
/* The 'real' main() program is in Rmain.c on Unix-alikes, and
55
   src/gnuwin/front-ends/graphappmain.c on Windows, unless of course
56
   R is embedded */
57
58
/* Global Variables:  For convenience, all interpreter global symbols
59
 * ================   are declared in Defn.h as extern -- and defined here.
60
 *
61
 * NOTE: This is done by using some preprocessor trickery.  If __MAIN__
62
 * is defined as above, there is a sneaky
63
 *     #define extern
64
 * so that the same code produces both declarations and definitions.
65
 *
66
 * This does not include user interface symbols which are included
67
 * in separate platform dependent modules.
68
 */
69
70
attribute_hidden
71
void Rf_callToplevelHandlers(SEXP expr, SEXP value, Rboolean succeeded,
72
           Rboolean visible);
73
74
static int ParseBrowser(SEXP, SEXP);
75
76
77
  /* Read-Eval-Print Loop [ =: REPL = repl ] with input from a file */
78
79
static void R_ReplFile(FILE *fp, SEXP rho)
80
76
{
81
76
    ParseStatus status;
82
76
    int savestack;
83
76
    RCNTXT cntxt;
84
85
76
    R_InitSrcRefState(&cntxt);
86
76
    savestack = R_PPStackTop;
87
5.09k
    for(;;) {
88
5.09k
  R_PPStackTop = savestack;
89
5.09k
  R_CurrentExpr = R_Parse1File(fp, 1, &status);
90
5.09k
  switch (status) {
91
3.04k
  case PARSE_NULL:
92
3.04k
      break;
93
1.97k
  case PARSE_OK:
94
1.97k
      R_Visible = FALSE;
95
1.97k
      R_EvalDepth = 0;
96
1.97k
      resetTimeLimits();
97
1.97k
      PROTECT(R_CurrentExpr);
98
1.97k
      R_CurrentExpr = eval(R_CurrentExpr, rho);
99
1.97k
      SET_SYMVALUE(R_LastvalueSymbol, R_CurrentExpr);
100
1.97k
      UNPROTECT(1);
101
1.97k
      if (R_Visible)
102
0
    PrintValueEnv(R_CurrentExpr, rho);
103
1.97k
      if( R_CollectWarnings )
104
0
    PrintWarnings();
105
1.97k
      break;
106
0
  case PARSE_ERROR:
107
0
      R_FinalizeSrcRefState();
108
0
      parseError(R_NilValue, R_ParseError);
109
0
      break;
110
76
  case PARSE_EOF:
111
76
      endcontext(&cntxt);
112
76
      R_FinalizeSrcRefState();
113
76
      return;
114
0
      break;
115
0
  case PARSE_INCOMPLETE:
116
      /* can't happen: just here to quieten -Wall */
117
0
      break;
118
5.09k
  }
119
5.09k
    }
120
76
}
121
122
/* Read-Eval-Print loop with interactive input */
123
static int prompt_type;
124
static char BrowsePrompt[20];
125
126
static const char *R_PromptString(int browselevel, int type)
127
0
{
128
0
    if (R_NoEcho) {
129
0
  BrowsePrompt[0] = '\0';
130
0
  return BrowsePrompt;
131
0
    }
132
0
    else {
133
0
  if(type == 1) {
134
0
      if(browselevel) {
135
0
    snprintf(BrowsePrompt, 20, "Browse[%d]> ", browselevel);
136
0
    return BrowsePrompt;
137
0
      }
138
0
      return CHAR(STRING_ELT(GetOption1(install("prompt")), 0));
139
0
  }
140
0
  else {
141
0
      return CHAR(STRING_ELT(GetOption1(install("continue")), 0));
142
0
  }
143
0
    }
144
0
}
145
146
/*
147
  This is a reorganization of the REPL (Read-Eval-Print Loop) to separate
148
  the loop from the actions of the body. The motivation is to make the iteration
149
  code (Rf_ReplIteration) available as a separately callable routine
150
  to avoid cutting and pasting it when one wants a single iteration
151
  of the loop. This is needed as we allow different implementations
152
  of event loops. Currently (summer 2002), we have a package in
153
  preparation that uses Rf_ReplIteration within either the
154
  Tcl or Gtk event loop and allows either (or both) loops to
155
  be used as a replacement for R's loop and take over the event
156
  handling for the R process.
157
158
  The modifications here are intended to leave the semantics of the REPL
159
  unchanged, just separate into routines. So the variables that maintain
160
  the state across iterations of the loop are organized into a structure
161
  and passed to Rf_ReplIteration() from Rf_ReplConsole().
162
*/
163
164
165
/**
166
  (local) Structure for maintaining and exchanging the state between
167
  Rf_ReplConsole and its worker routine Rf_ReplIteration which is the
168
  implementation of the body of the REPL.
169
170
  In the future, we may need to make this accessible to packages
171
  and so put it into one of the public R header files.
172
 */
173
typedef struct {
174
  ParseStatus    status;
175
  int            prompt_type;
176
  int            browselevel;
177
  unsigned char  buf[CONSOLE_BUFFER_SIZE+1];
178
  unsigned char *bufp;
179
} R_ReplState;
180
181
182
/**
183
  This is the body of the REPL.
184
  It attempts to parse the first line or expression of its input,
185
  and optionally request input from the user if none is available.
186
  If the input can be parsed correctly,
187
     i) the resulting expression is evaluated,
188
    ii) the result assigned to .Last.Value,
189
   iii) top-level task handlers are invoked.
190
191
 If the input cannot be parsed, i.e. there is a syntax error,
192
 it is incomplete, or we encounter an end-of-file, then we
193
 change the prompt accordingly.
194
195
 The "cursor" for the input buffer is moved to the next starting
196
 point, i.e. the end of the first line or after the first ;.
197
 */
198
attribute_hidden int
199
Rf_ReplIteration(SEXP rho, int savestack, int browselevel, R_ReplState *state)
200
0
{
201
    /* clear warnings that might have accumulated during a jump to top level */
202
0
    if (R_CollectWarnings)
203
0
  PrintWarnings();
204
205
0
    if(!*state->bufp) {
206
0
      R_Busy(0);
207
0
      if (R_ReadConsole(R_PromptString(browselevel, state->prompt_type),
208
0
            state->buf, CONSOLE_BUFFER_SIZE, 1) == 0)
209
0
    return(-1);
210
0
      state->bufp = state->buf;
211
0
    }
212
#ifdef SHELL_ESCAPE /* not default */
213
    if (*state->bufp == '!' && state->buf == state->bufp
214
        && state->prompt_type == 1) {
215
      R_system(&(state->buf[1]));
216
      state->buf[0] = '\0';
217
      return(0);
218
    }
219
#endif /* SHELL_ESCAPE */
220
0
    int c;
221
0
    while((c = *state->bufp)) {
222
0
      state->bufp++;
223
0
      R_IoBufferPutc(c, &R_ConsoleIob);
224
0
      if(c == ';' || c == '\n') break;
225
0
    }
226
227
0
    R_PPStackTop = savestack;
228
0
    R_CurrentExpr = R_Parse1Buffer(&R_ConsoleIob, 0, &state->status);
229
230
0
    switch(state->status) {
231
232
0
    case PARSE_NULL:
233
234
  /* The intention here is to break on CR but not on other
235
     null statements: see PR#9063 */
236
0
  if (browselevel && !R_DisableNLinBrowser
237
0
      && !strcmp((char *) state->buf, "\n")) return -1;
238
0
  R_IoBufferWriteReset(&R_ConsoleIob);
239
0
  state->prompt_type = 1;
240
0
  return 1;
241
242
0
    case PARSE_OK:
243
0
    {
244
0
  R_IoBufferReadReset(&R_ConsoleIob);
245
0
  R_CurrentExpr = R_Parse1Buffer(&R_ConsoleIob, 1, &state->status);
246
0
  int browsevalue = 0; /* -Wmaybe-uninit.. */
247
0
  if (browselevel) {
248
0
      browsevalue = ParseBrowser(R_CurrentExpr, rho);
249
0
      if(browsevalue == 1) return -1;
250
0
      if(browsevalue == 2) {
251
0
    R_IoBufferWriteReset(&R_ConsoleIob);
252
0
    return 0;
253
0
      }
254
      /* PR#15770 We don't want to step into expressions entered at the debug prompt.
255
       + PR#18885  Disable debugging of this environment for the duration of the call. */
256
0
      browsevalue = -RDEBUG(rho);
257
0
      SET_RDEBUG(rho, 0);
258
0
  }
259
0
  R_Visible = FALSE;
260
0
  R_EvalDepth = 0;
261
0
  resetTimeLimits();
262
0
  SEXP thisExpr = PROTECT(R_CurrentExpr);
263
0
  R_Busy(1);
264
0
  SEXP value = PROTECT(eval(thisExpr, rho));
265
0
  SET_SYMVALUE(R_LastvalueSymbol, value);
266
0
  if (NO_REFERENCES(value))
267
0
      INCREMENT_REFCNT(value);
268
0
  bool wasDisplayed = R_Visible;
269
0
  if (R_Visible)
270
0
      PrintValueEnv(value, rho);
271
0
  if (R_CollectWarnings)
272
0
      PrintWarnings();
273
0
  Rf_callToplevelHandlers(thisExpr, value, TRUE, wasDisplayed);
274
0
  R_CurrentExpr = value; /* Necessary? Doubt it. */
275
0
  UNPROTECT(2); /* thisExpr, value */
276
0
  if (browselevel && browsevalue < 0)
277
      /* Done evaluating REPL expression, continue stepping. */
278
0
      SET_RDEBUG(rho, 1);
279
0
  R_IoBufferWriteReset(&R_ConsoleIob);
280
0
  state->prompt_type = 1;
281
0
  return(1);
282
0
    }
283
0
    case PARSE_ERROR:
284
285
0
  state->prompt_type = 1;
286
0
  parseError(R_NilValue, 0);
287
0
  R_IoBufferWriteReset(&R_ConsoleIob);
288
0
  return(1);
289
290
0
    case PARSE_EOF:
291
  /* the parser thinks it is EOF but it may not have seen all of the
292
     input, so postpone the decision to exit until there is really
293
     no more input (the parser may be seeing a sequence of spaces)
294
     PR#15941 */
295
0
    case PARSE_INCOMPLETE:
296
0
  R_IoBufferReadReset(&R_ConsoleIob);
297
0
  state->prompt_type = 2;
298
0
  return(2);
299
0
    }
300
301
0
    return(0);
302
0
}
303
304
static void R_ReplConsole(SEXP rho, int savestack, int browselevel)
305
0
{
306
0
    int status;
307
0
    R_ReplState state = { PARSE_NULL, 1, 0, "", NULL};
308
309
0
    R_IoBufferWriteReset(&R_ConsoleIob);
310
0
    state.buf[0] = '\0';
311
0
    state.buf[CONSOLE_BUFFER_SIZE] = '\0';
312
    /* stopgap measure if line > CONSOLE_BUFFER_SIZE chars */
313
0
    state.bufp = state.buf;
314
#ifdef XTR_VERBOSE
315
    if(R_Verbose) // if(R_Verbose >= 2)  if ever the 'verbose' option  would be  positive integer
316
  REprintf(" >R_ReplConsole(): before \"for(;;)\" {main.c}\n");
317
#endif
318
0
    for(;;) {
319
0
  status = Rf_ReplIteration(rho, savestack, browselevel, &state);
320
0
  if(status < 0) {
321
0
    if (state.status == PARSE_INCOMPLETE)
322
0
      error(_("unexpected end of input"));
323
0
    return;
324
0
  }
325
0
    }
326
0
}
327
328
329
static unsigned char DLLbuf[CONSOLE_BUFFER_SIZE+1], *DLLbufp;
330
331
static void check_session_exit(void)
332
0
{
333
0
    if (! R_Interactive) {
334
  /* This funtion will be called again after a LONGJMP if an
335
     error is signaled from one of the functions called. The
336
     'exiting' variable identifies this and results in
337
     R_Suicide. */
338
0
  static bool exiting = FALSE;
339
0
  if (exiting)
340
0
      R_Suicide(_("error during cleanup\n"));
341
0
  else {
342
0
      exiting = TRUE;
343
0
      if (GetOption1(install("error")) != R_NilValue ||
344
0
    R_isTRUE(GetOption1(install("catch.script.errors")))
345
0
    ) {
346
0
    exiting = FALSE;
347
0
    return;
348
0
      }
349
0
      REprintf(_("Execution halted\n"));
350
0
      R_CleanUp(SA_NOSAVE, 1, 0); /* quit, no save, no .Last, status=1 */
351
0
  }
352
0
    }
353
0
}
354
355
void R_ReplDLLinit(void)
356
0
{
357
0
    if (SETJMP(R_Toplevel.cjmpbuf))
358
0
  check_session_exit();
359
0
    R_GlobalContext = R_ToplevelContext = R_SessionContext = &R_Toplevel;
360
0
    R_IoBufferWriteReset(&R_ConsoleIob);
361
0
    prompt_type = 1;
362
0
    DLLbuf[0] = DLLbuf[CONSOLE_BUFFER_SIZE] = '\0';
363
0
    DLLbufp = DLLbuf;
364
0
}
365
366
/* FIXME: this should be re-written to use Rf_ReplIteration
367
   since it gets out of sync with it over time */
368
int R_ReplDLLdo1(void)
369
0
{
370
0
    int c;
371
0
    ParseStatus status;
372
0
    SEXP rho = R_GlobalEnv, lastExpr;
373
374
0
    if(!*DLLbufp) {
375
0
  R_Busy(0);
376
0
  if (R_ReadConsole(R_PromptString(0, prompt_type), DLLbuf,
377
0
        CONSOLE_BUFFER_SIZE, 1) == 0)
378
0
      return -1;
379
0
  DLLbufp = DLLbuf;
380
0
    }
381
0
    while((c = *DLLbufp++)) {
382
0
  R_IoBufferPutc(c, &R_ConsoleIob);
383
0
  if(c == ';' || c == '\n') break;
384
0
    }
385
0
    R_PPStackTop = 0;
386
0
    R_CurrentExpr = R_Parse1Buffer(&R_ConsoleIob, 0, &status);
387
388
0
    switch(status) {
389
0
    case PARSE_NULL:
390
0
  R_IoBufferWriteReset(&R_ConsoleIob);
391
0
  prompt_type = 1;
392
0
  break;
393
0
    case PARSE_OK:
394
0
    {
395
0
  R_IoBufferReadReset(&R_ConsoleIob);
396
0
  R_CurrentExpr = R_Parse1Buffer(&R_ConsoleIob, 1, &status);
397
0
  R_Visible = FALSE;
398
0
  R_EvalDepth = 0;
399
0
  resetTimeLimits();
400
0
  PROTECT(R_CurrentExpr);
401
0
  R_Busy(1);
402
0
  lastExpr = R_CurrentExpr;
403
0
  R_CurrentExpr = eval(R_CurrentExpr, rho);
404
0
  SET_SYMVALUE(R_LastvalueSymbol, R_CurrentExpr);
405
0
  bool wasDisplayed = R_Visible;
406
0
  if (R_Visible)
407
0
      PrintValueEnv(R_CurrentExpr, rho);
408
0
  if (R_CollectWarnings)
409
0
      PrintWarnings();
410
0
  Rf_callToplevelHandlers(lastExpr, R_CurrentExpr, TRUE, wasDisplayed);
411
0
  UNPROTECT(1);
412
0
  R_IoBufferWriteReset(&R_ConsoleIob);
413
0
  R_Busy(0);
414
0
  prompt_type = 1;
415
0
  break;
416
0
    }
417
0
    case PARSE_ERROR:
418
0
  parseError(R_NilValue, 0);
419
0
  R_IoBufferWriteReset(&R_ConsoleIob);
420
0
  prompt_type = 1;
421
0
  break;
422
0
    case PARSE_INCOMPLETE:
423
0
  R_IoBufferReadReset(&R_ConsoleIob);
424
0
  prompt_type = 2;
425
0
  break;
426
0
    case PARSE_EOF:
427
0
  return -1;
428
0
  break;
429
0
    }
430
0
    return prompt_type;
431
0
}
432
433
/* Main Loop: It is assumed that at this point that operating system */
434
/* specific tasks (dialog window creation etc) have been performed. */
435
/* We can now print a greeting, run the .First function and then enter */
436
/* the read-eval-print loop. */
437
438
static void handleInterrupt(int dummy)
439
0
{
440
0
    R_interrupts_pending = 1;
441
0
    signal(SIGINT, handleInterrupt);
442
0
}
443
444
/* this flag is set if R internal code is using send() and does not
445
   want to trigger an error on SIGPIPE (e.g., the httpd code).
446
   [It is safer and more portable than other methods of handling
447
   broken pipes on send().]
448
 */
449
450
#ifndef Win32
451
// controlled by the internal http server in the internet module
452
int R_ignore_SIGPIPE = 0;
453
454
static void handlePipe(int dummy)
455
0
{
456
0
    signal(SIGPIPE, handlePipe);
457
0
    if (!R_ignore_SIGPIPE) error("ignoring SIGPIPE signal");
458
0
}
459
#endif
460
461
462
#ifdef Win32
463
static int num_caught = 0;
464
465
static void win32_segv(int signum)
466
{
467
    /* NB: stack overflow is not an access violation on Win32 */
468
    {   /* A simple customized print of the traceback */
469
  SEXP trace, p, q;
470
  int line = 1, i;
471
  PROTECT(trace = R_GetTraceback(0));
472
  if(trace != R_NilValue) {
473
      REprintf("\nTraceback:\n");
474
      for(p = trace; p != R_NilValue; p = CDR(p), line++) {
475
    q = CAR(p); /* a character vector */
476
    REprintf("%2d: ", line);
477
    for(i = 0; i < LENGTH(q); i++)
478
        REprintf("%s", CHAR(STRING_ELT(q, i)));
479
    REprintf("\n");
480
      }
481
      UNPROTECT(1);
482
  }
483
    }
484
    num_caught++;
485
    if(num_caught < 10) signal(signum, win32_segv);
486
    if(signum == SIGILL)
487
  error("caught access violation - continue with care");
488
    else
489
  error("caught access violation - continue with care");
490
}
491
#endif
492
493
#if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION) && defined(HAVE_WORKING_SIGACTION) && defined(HAVE_SIGEMPTYSET)
494
495
/* NB: this really isn't safe, but suffices for experimentation for now.
496
   In due course just set a flag and do this after the return.  OTOH,
497
   if we do want to bail out with a core dump, need to do that here.
498
499
   2005-12-17 BDR */
500
501
static unsigned char ConsoleBuf[CONSOLE_BUFFER_SIZE];
502
503
static void sigactionSegv(int signum, siginfo_t *ip, void *context)
504
0
{
505
    /* ensure R terminates if the handler segfaults (PR#18551) */
506
0
    signal(signum, SIG_DFL);
507
0
    char *s;
508
509
    /* First check for stack overflow if we know the stack position.
510
       We assume anything within 16Mb beyond the stack end is a stack overflow.
511
     */
512
0
    if(signum == SIGSEGV && (ip != (siginfo_t *)0) &&
513
0
       (intptr_t) R_CStackStart != -1) {
514
0
  uintptr_t addr = (uintptr_t) ip->si_addr;
515
0
  intptr_t diff = (R_CStackDir > 0) ? R_CStackStart - addr:
516
0
      addr - R_CStackStart;
517
0
  uintptr_t upper = 0x1000000;  /* 16Mb */
518
0
  if((intptr_t) R_CStackLimit != -1) upper += R_CStackLimit;
519
0
  if(diff > 0 && diff < upper) {
520
0
      REprintf(_("Error: segfault from C stack overflow\n"));
521
0
#if defined(linux) || defined(__linux__) || defined(__sun) || defined(sun)
522
0
      sigset_t ss;
523
0
      sigaddset(&ss, signum);
524
0
      sigprocmask(SIG_UNBLOCK, &ss, NULL);
525
0
#endif
526
0
      jump_to_toplevel();
527
0
  }
528
0
    }
529
530
    /* need to take off stack checking as stack base has changed */
531
0
    R_CStackLimit = (uintptr_t)-1;
532
533
    /* Do not translate these messages */
534
0
    REprintf("\n *** caught %s ***\n",
535
0
       signum == SIGILL ? "illegal operation" :
536
0
       signum == SIGBUS ? "bus error" : "segfault");
537
0
    if(ip != (siginfo_t *)0) {
538
0
  if(signum == SIGILL) {
539
540
0
      switch(ip->si_code) {
541
0
#ifdef ILL_ILLOPC
542
0
      case ILL_ILLOPC:
543
0
    s = "illegal opcode";
544
0
    break;
545
0
#endif
546
0
#ifdef ILL_ILLOPN
547
0
      case ILL_ILLOPN:
548
0
    s = "illegal operand";
549
0
    break;
550
0
#endif
551
0
#ifdef ILL_ILLADR
552
0
      case ILL_ILLADR:
553
0
    s = "illegal addressing mode";
554
0
    break;
555
0
#endif
556
0
#ifdef ILL_ILLTRP
557
0
      case ILL_ILLTRP:
558
0
    s = "illegal trap";
559
0
    break;
560
0
#endif
561
0
#ifdef ILL_COPROC
562
0
      case ILL_COPROC:
563
0
    s = "coprocessor error";
564
0
    break;
565
0
#endif
566
0
      default:
567
0
    s = "unknown";
568
0
    break;
569
0
      }
570
0
  } else if(signum == SIGBUS)
571
0
      switch(ip->si_code) {
572
0
#ifdef BUS_ADRALN
573
0
      case BUS_ADRALN:
574
0
    s = "invalid alignment";
575
0
    break;
576
0
#endif
577
0
#ifdef BUS_ADRERR /* not on macOS, apparently */
578
0
      case BUS_ADRERR:
579
0
    s = "non-existent physical address";
580
0
    break;
581
0
#endif
582
0
#ifdef BUS_OBJERR /* not on macOS, apparently */
583
0
      case BUS_OBJERR:
584
0
    s = "object specific hardware error";
585
0
    break;
586
0
#endif
587
0
      default:
588
0
    s = "unknown";
589
0
    break;
590
0
      }
591
0
  else
592
0
      switch(ip->si_code) {
593
0
#ifdef SEGV_MAPERR
594
0
      case SEGV_MAPERR:
595
0
    s = "memory not mapped";
596
0
    break;
597
0
#endif
598
0
#ifdef SEGV_ACCERR
599
0
      case SEGV_ACCERR:
600
0
    s = "invalid permissions";
601
0
    break;
602
0
#endif
603
0
      default:
604
0
    s = "unknown";
605
0
    break;
606
0
      }
607
0
  REprintf("address %p, cause '%s'\n", ip->si_addr, s);
608
0
    }
609
0
    {   /* A simple customized print of the traceback */
610
0
  SEXP trace, p, q;
611
0
  int line = 1, i;
612
0
  PROTECT(trace = R_GetTraceback(0));
613
0
  if(trace != R_NilValue) {
614
0
      REprintf("\nTraceback:\n");
615
0
      for(p = trace; p != R_NilValue; p = CDR(p), line++) {
616
0
    q = CAR(p); /* a character vector */
617
0
    REprintf("%2d: ", line);
618
0
    for(i = 0; i < LENGTH(q); i++)
619
0
        REprintf("%s", CHAR(STRING_ELT(q, i)));
620
0
    REprintf("\n");
621
0
      }
622
0
      UNPROTECT(1);
623
0
  }
624
0
    }
625
0
    if(R_Interactive) {
626
0
  REprintf("\nPossible actions:\n1: %s\n2: %s\n3: %s\n4: %s\n",
627
0
     "abort (with core dump, if enabled)",
628
0
     "normal R exit",
629
0
     "exit R without saving workspace",
630
0
     "exit R saving workspace");
631
0
  while(1) {
632
0
      if(R_ReadConsole("Selection: ", ConsoleBuf, CONSOLE_BUFFER_SIZE,
633
0
           0) > 0) {
634
0
    if(ConsoleBuf[0] == '1') break;
635
0
    if(ConsoleBuf[0] == '2') R_CleanUp(SA_DEFAULT, 0, 1);
636
0
    if(ConsoleBuf[0] == '3') R_CleanUp(SA_NOSAVE, 70, 0);
637
0
    if(ConsoleBuf[0] == '4') R_CleanUp(SA_SAVE, 71, 0);
638
0
      }
639
0
  }
640
0
  REprintf("R is aborting now ...\n");
641
0
    }
642
0
    else // non-interactively :
643
0
  REprintf("An irrecoverable exception occurred. R is aborting now ...\n");
644
0
    R_CleanTempDir();
645
    /* now do normal behaviour, e.g. core dump */
646
0
    raise(signum);
647
0
}
648
649
#ifndef SIGSTKSZ
650
# define SIGSTKSZ 8192    /* just a guess */
651
#endif
652
653
#ifdef HAVE_STACK_T
654
static stack_t sigstk;
655
#else
656
static struct sigaltstack sigstk;
657
#endif
658
static void *signal_stack;
659
660
0
#define R_USAGE 100000 /* Just a guess */
661
static void init_signal_handlers(void)
662
0
{
663
    /* On Windows, C signal handling functions are replaced by psignal.
664
       Initialization of a psignal Ctrl handler happens on the first
665
       signal-related call (typically here). Signal handlers for
666
       Ctrl signals set using C API before psignal initialization
667
       will have no effect. */
668
669
    /* Do not set the (since 2005 experimental) SEGV handler
670
       UI if R_NO_SEGV_HANDLER env var is non-empty.
671
       This is needed to debug crashes in the handler
672
       (which happen as they involve the console interface). */
673
0
    const char *val = getenv("R_NO_SEGV_HANDLER");
674
0
    if (!val || !*val) {
675
  /* <FIXME> may need to reinstall this if we do recover. */
676
0
  struct sigaction sa;
677
0
  signal_stack = malloc(SIGSTKSZ + R_USAGE);
678
0
  if (signal_stack != NULL) {
679
0
      sigstk.ss_sp = signal_stack;
680
0
      sigstk.ss_size = SIGSTKSZ + R_USAGE;
681
0
      sigstk.ss_flags = 0;
682
0
      if(sigaltstack(&sigstk, NULL) < 0)
683
0
    warning("failed to set alternate signal stack");
684
0
  } else
685
0
      warning("failed to allocate alternate signal stack");
686
0
  sa.sa_sigaction = sigactionSegv;
687
0
  sigemptyset(&sa.sa_mask);
688
0
  sa.sa_flags = SA_ONSTACK | SA_SIGINFO | SA_NODEFER;
689
0
  sigaction(SIGSEGV, &sa, NULL);
690
0
  sigaction(SIGILL, &sa, NULL);
691
0
#ifdef SIGBUS
692
0
  sigaction(SIGBUS, &sa, NULL);
693
0
#endif
694
0
    }
695
696
0
    if (signal(SIGINT, handleInterrupt) == SIG_IGN)
697
0
  signal(SIGINT, SIG_IGN);
698
0
    signal(SIGUSR1, onsigusr1);
699
0
    signal(SIGUSR2, onsigusr2);
700
0
    signal(SIGPIPE, handlePipe);
701
0
}
702
703
#else /* not sigaltstack and sigaction and sigemptyset*/
704
static void init_signal_handlers(void)
705
{
706
    if (signal(SIGINT,  handleInterrupt) == SIG_IGN)
707
  signal(SIGINT, SIG_IGN);
708
    signal(SIGUSR1, onsigusr1);
709
    signal(SIGUSR2, onsigusr2);
710
#ifndef Win32
711
    signal(SIGPIPE, handlePipe);
712
#else
713
    signal(SIGSEGV, win32_segv);
714
    signal(SIGILL, win32_segv);
715
#endif
716
}
717
#endif
718
719
720
static void R_LoadProfile(FILE *fparg, SEXP env)
721
114
{
722
114
    FILE * volatile fp = fparg; /* is this needed? */
723
114
    if (fp != NULL) {
724
38
  if (SETJMP(R_Toplevel.cjmpbuf))
725
0
      check_session_exit();
726
38
  else {
727
38
      R_GlobalContext = R_ToplevelContext = R_SessionContext = &R_Toplevel;
728
38
      R_ReplFile(fp, env);
729
38
  }
730
38
  fclose(fp);
731
38
    }
732
114
}
733
734
735
int R_SignalHandlers = 1;  /* Exposed in R_interface.h */
736
737
const char* get_workspace_name(void);  /* from startup.c */
738
739
attribute_hidden void BindDomain(char *R_Home)
740
38
{
741
38
#ifdef ENABLE_NLS
742
38
    char *localedir = NULL;
743
38
# if defined(LC_MESSAGES) && !defined(Win32)
744
38
    setlocale(LC_MESSAGES,"");
745
38
# endif
746
38
    textdomain(PACKAGE);
747
38
    char *p = getenv("R_TRANSLATIONS");
748
38
    if (p) Rasprintf_malloc(&localedir, "%s", p);
749
38
    else Rasprintf_malloc(&localedir, "%s/library/translations", R_Home);
750
38
    if (!localedir)
751
0
  R_Suicide("allocation failure in BindDomain");
752
38
    bindtextdomain(PACKAGE, localedir); // PACKAGE = DOMAIN = "R"
753
38
    bindtextdomain("R-base", localedir);
754
# ifdef _WIN32
755
    bindtextdomain("RGui", localedir);
756
# endif
757
38
    free(localedir);
758
38
#endif
759
38
}
760
761
/* #define DEBUG_STACK_DETECTION */
762
/* Not to be enabled in production use: the debugging code is more fragile
763
   than the detection itself. */
764
765
#ifdef DEBUG_STACK_DETECTION
766
static uintptr_t attribute_no_sanitizer_instrumentation almostFillStack() {
767
    volatile uintptr_t dummy;
768
769
    dummy = (uintptr_t) &dummy;
770
    if (R_CStackStart - R_CStackDir * R_CStackLimit + R_CStackDir * 1024 < R_CStackDir * dummy)
771
  return almostFillStack();
772
    else
773
  return dummy;
774
}
775
#endif
776
777
#ifdef Win32
778
static void invalid_parameter_handler_abort(
779
    const wchar_t* expression,
780
    const wchar_t* function,
781
    const wchar_t* file,
782
    unsigned int line,
783
    uintptr_t reserved)
784
{
785
    R_OutputCon = 2;
786
    R_ErrorCon = 2;
787
    REprintf(" ----------- FAILURE REPORT -------------- \n");
788
    REprintf(" --- failure: %s ---\n", "invalid parameter passed to a C runtime function");
789
    REprintf(" --- srcref --- \n");
790
    SrcrefPrompt("", R_getCurrentSrcref());
791
    REprintf("\n");
792
    REprintf(" --- call from context --- \n");
793
    PrintValue(R_GlobalContext->call);
794
    REprintf(" --- R stacktrace ---\n");
795
    printwhere();
796
    REprintf(" --- function from context --- \n");
797
    if (R_GlobalContext->callfun != NULL &&
798
        TYPEOF(R_GlobalContext->callfun) == CLOSXP)
799
        PrintValue(R_GlobalContext->callfun);
800
    REprintf(" --- function search by body ---\n");
801
    if (R_GlobalContext->callfun != NULL &&
802
        TYPEOF(R_GlobalContext->callfun) == CLOSXP)
803
        findFunctionForBody(R_ClosureExpr(R_GlobalContext->callfun));
804
    REprintf(" ----------- END OF FAILURE REPORT -------------- \n");
805
    R_Suicide("invalid parameter passed to a C runtime function");
806
}
807
808
extern void _invoke_watson(const wchar_t*, const wchar_t*, const wchar_t*,
809
    unsigned int, uintptr_t);
810
811
static void invalid_parameter_handler_watson(
812
    const wchar_t* expression,
813
    const wchar_t* function,
814
    const wchar_t* file,
815
    unsigned int line,
816
    uintptr_t reserved)
817
{
818
    _invoke_watson(expression, function, file, line, reserved);
819
}
820
#endif
821
822
void setup_Rmainloop(void)
823
38
{
824
38
    volatile int doneit;
825
38
    volatile SEXP baseNSenv;
826
38
    SEXP cmd;
827
38
    char deferred_warnings[12][250];
828
38
    volatile int ndeferred_warnings = 0;
829
830
#ifdef Win32
831
    {
832
  char *p = getenv("_R_WIN_CHECK_INVALID_PARAMETERS_");
833
  if (p && StringTrue(p))
834
      _set_invalid_parameter_handler(invalid_parameter_handler_abort);
835
  else if (p && !strcmp(p, "watson"))
836
      _set_invalid_parameter_handler(invalid_parameter_handler_watson);
837
    }
838
#endif
839
840
#ifdef DEBUG_STACK_DETECTION
841
    /* testing stack base and size detection */
842
    printf("stack limit %lu, start %lu dir %d \n",
843
  (unsigned long) R_CStackLimit,
844
        (unsigned long) R_CStackStart,
845
  R_CStackDir);
846
    uintptr_t firstb = R_CStackStart - R_CStackDir;
847
    printf("first accessible byte %lx\n", (unsigned long) firstb);
848
    if (R_CStackLimit != (uintptr_t)(-1)) {
849
        uintptr_t lastb = R_CStackStart - R_CStackDir * R_CStackLimit;
850
  printf("last accessible byte %lx\n", (unsigned long) lastb);
851
    }
852
    printf("accessing first byte...\n");
853
    volatile char dummy = *(char *)firstb;
854
    if (R_CStackLimit != (uintptr_t)(-1)) {
855
  /* have to access all bytes in order to map stack, e.g. on Linux
856
     just reading does not seem to always do the job, so better
857
     first almost fill up the stack using recursive function calls
858
   */
859
  printf("almost filling up stack...\n");
860
  printf("filled stack up to %lx\n", almostFillStack());
861
  /* the loop below writes outside the local variables and the frame,
862
     which is detected e.g. by ASAN as stack-buffer-overflow */
863
  printf("accessing all bytes...\n");
864
  for(uintptr_t o = 0; o < R_CStackLimit; o++)
865
      /* with exact bounds, o==-1 and o==R_CStackLimit will segfault */
866
      /* +dummy to silence -Wunused-but-set-variable */
867
      dummy = *((char *)firstb - R_CStackDir * o) + dummy;
868
    }
869
#endif
870
871
    /* In case this is a silly limit: 2^32 -3 has been seen and
872
     * casting to intptr_r relies on this being smaller than 2^31 on a
873
     * 32-bit platform. */
874
38
    if(R_CStackLimit > 100000000U)
875
38
  R_CStackLimit = (uintptr_t)-1;
876
    /* make sure we have enough head room to handle errors */
877
38
    if(R_CStackLimit != -1)
878
0
  R_CStackLimit = (uintptr_t)(0.95 * R_CStackLimit);
879
880
38
    InitConnections(); /* needed to get any output at all */
881
882
    /* Initialize the interpreter's internal structures. */
883
884
38
#ifdef HAVE_LOCALE_H
885
#ifdef Win32
886
    {
887
  char allbuf[1000]; /* Windows' locales can be very long */
888
  char *p, *lcall;
889
890
  p = getenv("LC_ALL");
891
  if(p) {
892
      strncpy(allbuf, p, sizeof(allbuf));
893
      allbuf[1000 - 1] = '\0';
894
      lcall = allbuf;
895
  } else
896
      lcall = NULL;
897
898
  /* We'd like to use warning, but need to defer.
899
     Also cannot translate. */
900
901
  p = lcall ? lcall : getenv("LC_COLLATE");
902
  if(!setlocale(LC_COLLATE, p ? p : ""))
903
      snprintf(deferred_warnings[ndeferred_warnings++], 250,
904
         "Setting LC_COLLATE=%.200s failed\n", p);
905
906
  p = lcall ? lcall : getenv("LC_CTYPE");
907
  if(!setlocale(LC_CTYPE, p ? p : ""))
908
      snprintf(deferred_warnings[ndeferred_warnings++], 250,
909
         "Setting LC_CTYPE=%.200s failed\n", p);
910
911
  p = lcall ? lcall : getenv("LC_MONETARY");
912
  if(!setlocale(LC_MONETARY, p ? p : ""))
913
      snprintf(deferred_warnings[ndeferred_warnings++], 250,
914
         "Setting LC_MONETARY=%.200s failed\n", p);
915
916
  p = lcall ? lcall : getenv("LC_TIME");
917
  if(!setlocale(LC_TIME, p ? p : ""))
918
      snprintf(deferred_warnings[ndeferred_warnings++], 250,
919
         "Setting LC_TIME=%.200s failed\n", p);
920
921
  /* We set R_ARCH here: Unix does it in the shell front-end */
922
  char Rarch[30];
923
  strcpy(Rarch, "R_ARCH=");
924
# ifdef R_ARCH
925
  if (strlen(R_ARCH) > 0) {
926
      strcat(Rarch, "/");
927
      strcat(Rarch, R_ARCH);
928
  }
929
# endif
930
  putenv(Rarch);
931
    }
932
#else /* not Win32 */
933
934
38
{  /* Avoid annoying warnings if LANG and LC_ALL are unset or empty.
935
      This happens e.g. on Mac when primary language clash with region,
936
      like English in Denmark or Germany.
937
938
      If LANG or LC_ALL has been set to a non-existing locale, we assume
939
      that the user wants to ne informed. */
940
941
38
    const char *s;
942
38
    int quiet;
943
944
38
    quiet = !( ((s = getenv("LANG")) && *s) || ((s = getenv("LC_ALL")) && *s) );
945
946
38
    if(!setlocale(LC_CTYPE, "") && !quiet)
947
0
  snprintf(deferred_warnings[ndeferred_warnings++], 250,
948
949
0
     "Setting LC_CTYPE failed, using \"C\"\n");
950
38
    if(!setlocale(LC_COLLATE, "") && !quiet)
951
0
  snprintf(deferred_warnings[ndeferred_warnings++], 250,
952
0
     "Setting LC_COLLATE failed, using \"C\"\n");
953
38
    if(!setlocale(LC_TIME, "") && !quiet)
954
0
  snprintf(deferred_warnings[ndeferred_warnings++], 250,
955
0
     "Setting LC_TIME failed, using \"C\"\n");
956
38
# if defined(ENABLE_NLS) && defined(LC_MESSAGES)
957
38
    if(!setlocale(LC_MESSAGES, "") && !quiet)
958
0
  snprintf(deferred_warnings[ndeferred_warnings++], 250,
959
0
     "Setting LC_MESSAGES failed, using \"C\"\n");
960
38
# endif
961
    /* NB: we do not set LC_NUMERIC */
962
38
# ifdef LC_MONETARY
963
38
    if(!setlocale(LC_MONETARY, "") && !quiet)
964
0
  snprintf(deferred_warnings[ndeferred_warnings++], 250,
965
0
     "Setting LC_MONETARY failed, using \"C\"\n");
966
38
# endif
967
38
# ifdef LC_PAPER
968
38
    if(!setlocale(LC_PAPER, "") && !quiet)
969
0
  snprintf(deferred_warnings[ndeferred_warnings++], 250,
970
0
     "Setting LC_PAPER failed, using \"C\"\n");
971
38
# endif
972
38
# ifdef LC_MEASUREMENT
973
38
    if(!setlocale(LC_MEASUREMENT, "") && !quiet)
974
0
  snprintf(deferred_warnings[ndeferred_warnings++], 250,
975
0
     "Setting LC_MEASUREMENT failed, using \"C\"\n");
976
38
# endif
977
38
}
978
38
#endif /* not Win32 */
979
38
#endif
980
981
    /* make sure srand is called before R_tmpnam, PR#14381 */
982
38
    srand(TimeToSeed());
983
984
38
    InitArithmetic();
985
38
    InitTempDir(); /* must be before InitEd */
986
38
    InitMemory();
987
38
    InitStringHash(); /* must be before InitNames */
988
38
    InitBaseEnv();
989
38
    InitNames(); /* must be after InitBaseEnv to use R_EmptyEnv */
990
38
    InitParser();  /* must be after InitMemory, InitNames */
991
38
    InitGlobalEnv();
992
38
    InitDynload();
993
38
    InitOptions();
994
38
    InitEd();
995
38
    InitGraphics();
996
38
    InitTypeTables(); /* must be before InitS3DefaultTypes */
997
38
    InitS3DefaultTypes();
998
38
    PrintDefaults();
999
38
    R_InitConditions();
1000
1001
38
    R_Is_Running = 1;
1002
38
    R_check_locale();
1003
#ifdef Win32
1004
    if (localeCP && systemCP != localeCP)
1005
        /* For now, don't warn for localeCP == 0, but it can cause problems
1006
           as well. Keep in step with do_setlocale. */
1007
  snprintf(deferred_warnings[ndeferred_warnings++], 250,
1008
            "Using locale code page other than %d%s may cause problems.",
1009
            systemCP, systemCP == 65001 ? " (\"UTF-8\")" : "");
1010
#endif
1011
    /* Initialize the global context for error handling. */
1012
    /* This provides a target for any non-local gotos */
1013
    /* which occur during error handling */
1014
1015
38
    R_Toplevel.nextcontext = NULL;
1016
38
    R_Toplevel.callflag = CTXT_TOPLEVEL;
1017
38
    R_Toplevel.cstacktop = 0;
1018
38
    R_Toplevel.gcenabled = R_GCEnabled;
1019
38
    R_Toplevel.promargs = R_NilValue;
1020
38
    R_Toplevel.callfun = R_NilValue;
1021
38
    R_Toplevel.call = R_NilValue;
1022
38
    R_Toplevel.cloenv = R_BaseEnv;
1023
38
    R_Toplevel.sysparent = R_BaseEnv;
1024
38
    R_Toplevel.conexit = R_NilValue;
1025
38
    R_Toplevel.vmax = NULL;
1026
38
    R_Toplevel.nodestack = R_BCNodeStackTop;
1027
38
    R_Toplevel.bcprottop = R_BCProtTop;
1028
38
    R_Toplevel.cend = NULL;
1029
38
    R_Toplevel.cenddata = NULL;
1030
38
    R_Toplevel.intsusp = FALSE;
1031
38
    R_Toplevel.handlerstack = R_HandlerStack;
1032
38
    R_Toplevel.restartstack = R_RestartStack;
1033
38
    R_Toplevel.srcref = R_NilValue;
1034
38
    R_Toplevel.prstack = NULL;
1035
38
    R_Toplevel.returnValue = SEXP_TO_STACKVAL(NULL);
1036
38
    R_Toplevel.evaldepth = 0;
1037
38
    R_Toplevel.browserfinish = 0;
1038
38
    R_GlobalContext = R_ToplevelContext = R_SessionContext = &R_Toplevel;
1039
38
    R_ExitContext = NULL;
1040
1041
38
    R_Warnings = R_NilValue;
1042
1043
    /* This is the same as R_BaseEnv, but this marks the environment
1044
       of functions as the namespace and not the package. */
1045
38
    baseNSenv = R_BaseNamespace;
1046
1047
    /* Set up some global variables */
1048
38
    Init_R_Variables(baseNSenv);
1049
1050
    /* On initial entry we open the base language package and begin by
1051
       running the repl on it.
1052
       If there is an error we pass on to the repl.
1053
       Perhaps it makes more sense to quit gracefully?
1054
    */
1055
1056
#ifdef RMIN_ONLY
1057
    /* This is intended to support a minimal build for experimentation. */
1058
    if (R_SignalHandlers) init_signal_handlers();
1059
#else
1060
38
    FILE *fp = R_OpenLibraryFile("base");
1061
38
    if (fp == NULL)
1062
0
  R_Suicide(_("unable to open the base package\n"));
1063
1064
38
    doneit = 0;
1065
38
    if (SETJMP(R_Toplevel.cjmpbuf))
1066
0
  check_session_exit();
1067
38
    R_GlobalContext = R_ToplevelContext = R_SessionContext = &R_Toplevel;
1068
38
    if (R_SignalHandlers) init_signal_handlers();
1069
38
    if (!doneit) {
1070
38
  doneit = 1;
1071
38
  R_ReplFile(fp, baseNSenv);
1072
38
    }
1073
38
    fclose(fp);
1074
38
#endif
1075
1076
    /* This is where we source the system-wide, the site's and the
1077
       user's profile (in that order).  If there is an error, we
1078
       drop through to further processing.
1079
    */
1080
38
    R_IoBufferInit(&R_ConsoleIob);
1081
38
    R_LoadProfile(R_OpenSysInitFile(), baseNSenv);
1082
    /* These are the same bindings, so only lock them once */
1083
38
    R_LockEnvironment(R_BaseNamespace, TRUE);
1084
38
    R_LockEnvironment(R_BaseEnv, FALSE);
1085
    /* At least temporarily unlock some bindings used in graphics */
1086
38
    R_unLockBinding(R_DeviceSymbol, R_BaseEnv);
1087
38
    R_unLockBinding(R_DevicesSymbol, R_BaseEnv);
1088
1089
    /* require(methods) if it is in the default packages */
1090
38
    doneit = 0;
1091
38
    if (SETJMP(R_Toplevel.cjmpbuf))
1092
0
  check_session_exit();
1093
38
    R_GlobalContext = R_ToplevelContext = R_SessionContext = &R_Toplevel;
1094
38
    if (!doneit) {
1095
38
  doneit = 1;
1096
38
  PROTECT(cmd = install(".OptRequireMethods"));
1097
38
  R_CurrentExpr = R_findVar(cmd, R_GlobalEnv);
1098
38
  if (R_CurrentExpr != R_UnboundValue &&
1099
38
      TYPEOF(R_CurrentExpr) == CLOSXP) {
1100
38
    PROTECT(R_CurrentExpr = lang1(cmd));
1101
38
    R_CurrentExpr = eval(R_CurrentExpr, R_BaseEnv);
1102
38
    UNPROTECT(1);
1103
38
  }
1104
38
  UNPROTECT(1);
1105
38
    }
1106
1107
38
    if (strcmp(R_GUIType, "Tk") == 0) {
1108
0
  char *buf = NULL;
1109
1110
0
  Rasprintf_malloc(&buf, "%s/library/tcltk/exec/Tk-frontend.R", R_Home);
1111
0
  if (!buf)
1112
0
      R_Suicide("allocation failure in setup_Rmainloop");
1113
0
  R_LoadProfile(R_fopen(buf, "r"), R_GlobalEnv);
1114
0
  free(buf);
1115
0
    }
1116
1117
    /* Print a platform and version dependent greeting and a pointer to
1118
     * the copyleft.
1119
     */
1120
38
    if(!R_Quiet) PrintGreeting();
1121
1122
38
    R_LoadProfile(R_OpenSiteFile(), R_GlobalEnv);
1123
    /* The system profile creates an active binding in global environment
1124
       to capture writes to .Library.site executed in the site profile. This
1125
       effectively modifies .Library.site in the base environment to mimick
1126
       previous behavior when the site profile was run in the base
1127
       environment. */
1128
38
    R_removeVarFromFrame(install(".Library.site"), R_GlobalEnv);
1129
38
    R_LoadProfile(R_OpenInitFile(), R_GlobalEnv);
1130
1131
    /* This is where we try to load a user's saved data.
1132
       The right thing to do here is very platform dependent.
1133
       E.g. under Unix we look in a special hidden file and on the Mac
1134
       we look in any documents which might have been double clicked on
1135
       or dropped on the application.
1136
    */
1137
38
    doneit = 0;
1138
38
    if (SETJMP(R_Toplevel.cjmpbuf))
1139
0
  check_session_exit();
1140
38
    R_GlobalContext = R_ToplevelContext = R_SessionContext = &R_Toplevel;
1141
38
    if (!doneit) {
1142
38
  doneit = 1;
1143
38
  R_InitialData();
1144
38
    }
1145
0
    else {
1146
0
  if (SETJMP(R_Toplevel.cjmpbuf))
1147
0
      check_session_exit();
1148
0
  else {
1149
0
          warning(_("unable to restore saved data in %s\n"), get_workspace_name());
1150
0
  }
1151
0
    }
1152
1153
    /* Initial Loading is done.
1154
       At this point we try to invoke the .First Function.
1155
       If there is an error we continue. */
1156
1157
38
    doneit = 0;
1158
38
    if (SETJMP(R_Toplevel.cjmpbuf))
1159
0
  check_session_exit();
1160
38
    R_GlobalContext = R_ToplevelContext = R_SessionContext = &R_Toplevel;
1161
38
    if (!doneit) {
1162
38
  doneit = 1;
1163
38
  PROTECT(cmd = install(".First"));
1164
38
  R_CurrentExpr = R_findVar(cmd, R_GlobalEnv);
1165
38
  if (R_CurrentExpr != R_UnboundValue &&
1166
0
      TYPEOF(R_CurrentExpr) == CLOSXP) {
1167
0
    PROTECT(R_CurrentExpr = lang1(cmd));
1168
0
    R_CurrentExpr = eval(R_CurrentExpr, R_GlobalEnv);
1169
0
    UNPROTECT(1);
1170
0
  }
1171
38
  UNPROTECT(1);
1172
38
    }
1173
    /* Try to invoke the .First.sys function, which loads the default packages.
1174
       If there is an error we continue. */
1175
1176
38
    doneit = 0;
1177
38
    if (SETJMP(R_Toplevel.cjmpbuf))
1178
0
  check_session_exit();
1179
38
    R_GlobalContext = R_ToplevelContext = R_SessionContext = &R_Toplevel;
1180
38
    if (!doneit) {
1181
38
  doneit = 1;
1182
38
  PROTECT(cmd = install(".First.sys"));
1183
38
  R_CurrentExpr = R_findVar(cmd, baseNSenv);
1184
38
  if (R_CurrentExpr != R_UnboundValue &&
1185
38
      TYPEOF(R_CurrentExpr) == CLOSXP) {
1186
38
    PROTECT(R_CurrentExpr = lang1(cmd));
1187
38
    R_CurrentExpr = eval(R_CurrentExpr, R_BaseEnv);
1188
38
    UNPROTECT(1);
1189
38
  }
1190
38
  UNPROTECT(1);
1191
38
    }
1192
38
    {
1193
38
  int i;
1194
38
  for(i = 0 ; i < ndeferred_warnings; i++)
1195
0
      warning("%s", deferred_warnings[i]);
1196
38
    }
1197
38
    if (R_CollectWarnings) {
1198
0
  REprintf(_("During startup - "));
1199
0
  PrintWarnings();
1200
0
    }
1201
38
    if(R_Verbose)
1202
0
  REprintf(" ending setup_Rmainloop(): R_Interactive = %d {main.c}\n",
1203
0
     R_Interactive);
1204
1205
    /* trying to do this earlier seems to run into bootstrapping issues. */
1206
38
#ifndef RMIN_ONLY
1207
38
    doneit = 0;
1208
38
    if (SETJMP(R_Toplevel.cjmpbuf))
1209
0
  check_session_exit();
1210
38
    R_GlobalContext = R_ToplevelContext = R_SessionContext = &R_Toplevel;
1211
38
    if (!doneit) {
1212
38
  doneit = 1;
1213
38
  R_init_jit_enabled();
1214
38
    } else
1215
0
  R_Suicide(_("unable to initialize the JIT\n"));
1216
38
#endif
1217
38
    R_Is_Running = 2;
1218
38
}
1219
1220
extern SA_TYPE SaveAction; /* from src/main/startup.c */
1221
1222
static void end_Rmainloop(void)
1223
0
{
1224
    /* refrain from printing trailing '\n' in no-echo mode */
1225
0
    if (!R_NoEcho)
1226
0
  Rprintf("\n");
1227
    /* run the .Last function. If it gives an error, will drop back to main
1228
       loop. */
1229
0
    R_CleanUp(SA_DEFAULT, 0, 1);
1230
0
}
1231
1232
void run_Rmainloop(void)
1233
0
{
1234
    /* Here is the real R read-eval-loop. */
1235
    /* We handle the console until end-of-file. */
1236
0
    if (SETJMP(R_Toplevel.cjmpbuf))
1237
0
  check_session_exit();
1238
0
    R_GlobalContext = R_ToplevelContext = R_SessionContext = &R_Toplevel;
1239
0
    R_ReplConsole(R_GlobalEnv, 0, 0);
1240
0
    end_Rmainloop(); /* must go here */
1241
0
}
1242
1243
void mainloop(void)
1244
0
{
1245
0
    setup_Rmainloop();
1246
0
    run_Rmainloop();
1247
0
}
1248
1249
/*this functionality now appears in 3
1250
  places-jump_to_toplevel/profile/here */
1251
1252
attribute_hidden void printwhere(void)
1253
0
{
1254
0
  RCNTXT *cptr;
1255
0
  int lct = 1;
1256
1257
0
  for (cptr = R_GlobalContext; cptr; cptr = cptr->nextcontext) {
1258
0
    if ((cptr->callflag & (CTXT_FUNCTION | CTXT_BUILTIN)) &&
1259
0
  (TYPEOF(cptr->call) == LANGSXP)) {
1260
0
  Rprintf("where %d", lct++);
1261
0
  SEXP sref;
1262
0
  if (cptr->srcref == R_InBCInterpreter)
1263
0
      sref = R_findBCInterpreterSrcref(cptr);
1264
0
  else
1265
0
      sref = cptr->srcref;
1266
0
  SrcrefPrompt("", sref);
1267
0
  PrintValue(cptr->call);
1268
0
    }
1269
0
  }
1270
0
  Rprintf("\n");
1271
0
}
1272
1273
static void printBrowserHelp(void)
1274
0
{
1275
0
    Rprintf("n          next\n");
1276
0
    Rprintf("s          step into\n");
1277
0
    Rprintf("f          finish\n");
1278
0
    Rprintf("c or cont  continue\n");
1279
0
    Rprintf("Q          quit\n");
1280
0
    Rprintf("where      show stack\n");
1281
0
    Rprintf("help       show help\n");
1282
0
    Rprintf("<expr>     evaluate expression\n");
1283
0
}
1284
1285
static int ParseBrowser(SEXP CExpr, SEXP rho)
1286
0
{
1287
0
    int rval = 0;
1288
0
    if (isSymbol(CExpr)) {
1289
0
  const char *expr = CHAR(PRINTNAME(CExpr));
1290
0
  if (!strcmp(expr, "c") || !strcmp(expr, "cont")) {
1291
0
      rval = 1;
1292
0
      SET_RDEBUG(rho, 0);
1293
0
  } else if (!strcmp(expr, "f")) {
1294
0
      rval = 1;
1295
0
      RCNTXT *cntxt = R_GlobalContext;
1296
0
      while (cntxt != R_ToplevelContext
1297
0
          && !(cntxt->callflag & (CTXT_RETURN | CTXT_LOOP))) {
1298
0
    cntxt = cntxt->nextcontext;
1299
0
      }
1300
0
      cntxt->browserfinish = 1;
1301
0
      SET_RDEBUG(rho, 1);
1302
0
      R_BrowserLastCommand = 'f';
1303
0
  } else if (!strcmp(expr, "help")) {
1304
0
      rval = 2;
1305
0
      printBrowserHelp();
1306
0
  } else if (!strcmp(expr, "n")) {
1307
0
      rval = 1;
1308
0
      SET_RDEBUG(rho, 1);
1309
0
      R_BrowserLastCommand = 'n';
1310
0
  } else if (!strcmp(expr, "Q")) {
1311
1312
      /* this is really dynamic state that should be managed as such */
1313
0
      SET_RDEBUG(rho, 0); /*PR#1721*/
1314
1315
0
      jump_to_toplevel();
1316
0
  } else if (!strcmp(expr, "s")) {
1317
0
      rval = 1;
1318
0
      SET_RDEBUG(rho, 1);
1319
0
      R_BrowserLastCommand = 's';
1320
0
  } else if (!strcmp(expr, "where")) {
1321
0
      rval = 2;
1322
0
      printwhere();
1323
      /* SET_RDEBUG(rho, 1); */
1324
0
  } else if (!strcmp(expr, "r")) {
1325
0
      SEXP hooksym = install(".tryResumeInterrupt");
1326
0
      if (SYMVALUE(hooksym) != R_UnboundValue) {
1327
0
    SEXP hcall;
1328
0
    R_Busy(1);
1329
0
    PROTECT(hcall = LCONS(hooksym, R_NilValue));
1330
0
    eval(hcall, R_BaseEnv);
1331
0
    UNPROTECT(1);
1332
0
      }
1333
0
  }
1334
0
    }
1335
1336
0
    return rval;
1337
0
}
1338
1339
/* There's another copy of this in eval.c */
1340
static void PrintCall(SEXP call, SEXP rho)
1341
0
{
1342
0
    int old_bl = R_BrowseLines,
1343
0
  blines = asInteger(GetOption1(install("deparse.max.lines")));
1344
0
    if(blines != NA_INTEGER && blines > 0)
1345
0
  R_BrowseLines = blines;
1346
1347
0
    R_PrintData pars;
1348
0
    PrintInit(&pars, rho);
1349
0
    PrintValueRec(call, &pars);
1350
1351
0
    R_BrowseLines = old_bl;
1352
0
}
1353
1354
static int countBrowserContexts(void)
1355
0
{
1356
    /* passing TRUE for the second argument seems to over-count */
1357
0
    return countContexts(CTXT_BROWSER, FALSE);
1358
0
}
1359
1360
#ifdef USE_BROWSER_HOOK
1361
struct callBrowserHookData { SEXP hook, cond, rho; };
1362
1363
static SEXP callBrowserHook(void *data)
1364
{
1365
    struct callBrowserHookData *bhdata = data;
1366
    SEXP hook = bhdata-> hook;
1367
    SEXP cond = bhdata->cond;
1368
    SEXP rho = bhdata->rho;
1369
    SEXP args = CONS(hook, CONS(cond, CONS(rho, R_NilValue)));
1370
    SEXP hcall = LCONS(hook, args);
1371
    PROTECT(hcall);
1372
    R_SetOption(install("browser.hook"), R_NilValue);
1373
    SEXP val = eval(hcall, R_GlobalEnv);
1374
    UNPROTECT(1); /* hcall */
1375
    return val;
1376
}
1377
1378
static void restoreBrowserHookOption(void *data, bool jump)
1379
{
1380
    struct callBrowserHookData *bhdata = data;
1381
    SEXP hook = bhdata-> hook;
1382
    R_SetOption(install("browser.hook"), hook); // also on jumps
1383
}
1384
1385
static void R_browserRepl(SEXP rho)
1386
{
1387
    /* save some stuff -- shouldn't be needed unless REPL is sloppy */
1388
    int savestack = R_PPStackTop;
1389
    SEXP topExp = PROTECT(R_CurrentExpr);
1390
    RCNTXT *saveToplevelContext = R_ToplevelContext;
1391
    RCNTXT *saveGlobalContext = R_GlobalContext;
1392
1393
    int browselevel = countBrowserContexts();
1394
    R_ReplConsole(rho, savestack, browselevel);
1395
1396
    /* restore the saved stuff */
1397
    R_CurrentExpr = topExp;
1398
    UNPROTECT(1); /* topExp */
1399
    R_PPStackTop = savestack;
1400
    R_CurrentExpr = topExp;
1401
    R_ToplevelContext = saveToplevelContext;
1402
    R_GlobalContext = saveGlobalContext;
1403
}
1404
#endif
1405
1406
/* browser(text = "", condition = NULL, expr = TRUE, skipCalls = 0L)
1407
 * ------- but also called from ./eval.c */
1408
attribute_hidden SEXP do_browser(SEXP call, SEXP op, SEXP args, SEXP rho)
1409
0
{
1410
0
    RCNTXT *saveToplevelContext;
1411
0
    RCNTXT *saveGlobalContext;
1412
0
    RCNTXT thiscontext, returncontext, *cptr;
1413
0
    int savestack, browselevel;
1414
0
    SEXP ap, topExp, argList;
1415
1416
    /* Cannot call checkArity(op, args), because "op" may be a closure  */
1417
    /* or a primitive other than "browser".  */
1418
1419
    /* argument matching */
1420
0
    PROTECT(ap = list4(R_NilValue, R_NilValue, R_NilValue, R_NilValue));
1421
0
    SET_TAG(ap,  install("text"));
1422
0
    SET_TAG(CDR(ap), install("condition"));
1423
0
    SET_TAG(CDDR(ap), install("expr"));
1424
0
    SET_TAG(CDDDR(ap), install("skipCalls"));
1425
#ifdef USE_BROWSER_HOOK
1426
    SETCDR(CDDDR(ap), CONS(R_NilValue, R_NilValue));
1427
    SET_TAG(CDR(CDDDR(ap)), install("ignoreHook"));
1428
#endif
1429
0
    argList = matchArgs_RC(ap, args, call);
1430
0
    UNPROTECT(1);
1431
0
    PROTECT(argList);
1432
    /* substitute defaults */
1433
0
    if(CAR(argList) == R_MissingArg)
1434
0
  SETCAR(argList, mkString(""));
1435
0
    if(CADR(argList) == R_MissingArg)
1436
0
  SETCAR(CDR(argList), R_NilValue);
1437
0
    if(CADDR(argList) == R_MissingArg)
1438
0
  SETCAR(CDDR(argList), ScalarLogical(1));
1439
0
    if(CADDDR(argList) == R_MissingArg)
1440
0
  SETCAR(CDDDR(argList), ScalarInteger(0));
1441
#ifdef USE_BROWSER_HOOK
1442
    if(CAR(CDR(CDDDR(argList))) == R_MissingArg)
1443
  SETCAR(CDR(CDDDR(argList)), ScalarLogical(FALSE));
1444
#endif
1445
1446
    /* return if 'expr' is not TRUE */
1447
0
    SEXP expr = CADDR(argList);
1448
0
    if (! asLogical(expr)) {
1449
0
  UNPROTECT(1);
1450
0
  return R_NilValue;
1451
0
    }
1452
1453
#ifdef USE_BROWSER_HOOK
1454
    /* allow environment to use to be provides as the 'expr' argument */
1455
    if (TYPEOF(expr) == ENVSXP)
1456
  rho = expr;
1457
1458
    bool ignoreHook = asBool2(CAR(CDR(CDDDR(argList))), call);
1459
    if (ignoreHook) {
1460
        R_browserRepl(rho);
1461
        UNPROTECT(1); /* argList */
1462
        return R_ReturnedValue;
1463
    }
1464
#endif
1465
1466
    /* trap non-interactive debugger invocation */
1467
0
    if(! R_Interactive) {
1468
0
        char *p = getenv("_R_CHECK_BROWSER_NONINTERACTIVE_");
1469
0
        if (p != NULL && StringTrue(p))
1470
0
            error(_("non-interactive browser() -- left over from debugging?"));
1471
0
    }
1472
1473
    /* Save the evaluator state information */
1474
    /* so that it can be restored on exit. */
1475
1476
0
    browselevel = countBrowserContexts();
1477
0
    savestack = R_PPStackTop;
1478
0
    PROTECT(topExp = R_CurrentExpr);
1479
0
    saveToplevelContext = R_ToplevelContext;
1480
0
    saveGlobalContext = R_GlobalContext;
1481
1482
0
    if (!RDEBUG(rho)) {
1483
0
  int skipCalls = asInteger(CADDDR(argList));
1484
0
  cptr = R_GlobalContext;
1485
#ifdef USE_BROWSER_HOOK
1486
  if (! ignoreHook)
1487
      /* skip over the hook closure on the stack */
1488
      while ((!(cptr->callflag & CTXT_FUNCTION) || cptr->cloenv != rho)
1489
       && cptr->callflag )
1490
      cptr = cptr->nextcontext;
1491
#endif
1492
0
  while ( ( !(cptr->callflag & CTXT_FUNCTION) || skipCalls--)
1493
0
    && cptr->callflag )
1494
0
      cptr = cptr->nextcontext;
1495
0
  Rprintf("Called from: ");
1496
0
  if( cptr != R_ToplevelContext ) {
1497
0
      PrintCall(cptr->call, rho);
1498
0
      SET_RDEBUG(cptr->cloenv, 1);
1499
0
  } else
1500
0
      Rprintf("top level \n");
1501
1502
0
  R_BrowseLines = 0;
1503
0
    }
1504
1505
0
    R_ReturnedValue = R_NilValue;
1506
1507
    /* Here we establish two contexts.  The first */
1508
    /* of these provides a target for return */
1509
    /* statements which a user might type at the */
1510
    /* browser prompt.  The (optional) second one */
1511
    /* acts as a target for error returns. */
1512
1513
0
    begincontext(&returncontext, CTXT_BROWSER, call, rho,
1514
0
     R_BaseEnv, argList, R_NilValue);
1515
0
    if (!SETJMP(returncontext.cjmpbuf)) {
1516
0
  begincontext(&thiscontext, CTXT_RESTART, R_NilValue, rho,
1517
0
         R_BaseEnv, R_NilValue, R_NilValue);
1518
0
  if (SETJMP(thiscontext.cjmpbuf)) {
1519
0
      SET_RESTART_BIT_ON(thiscontext.callflag);
1520
0
      R_ReturnedValue = R_NilValue;
1521
0
      R_Visible = FALSE;
1522
0
  }
1523
0
  R_GlobalContext = &thiscontext;
1524
0
  R_InsertRestartHandlers(&thiscontext, "browser");
1525
#ifdef USE_BROWSER_HOOK
1526
  /* if a browser hook is provided, call it and use the result */
1527
  SEXP hook = ignoreHook ?
1528
      R_NilValue : GetOption1(install("browser.hook"));
1529
  if (isFunction(hook)) {
1530
      struct callBrowserHookData bhdata = {
1531
          .hook = hook, .cond = CADR(argList), .rho = rho
1532
      };
1533
      R_ReturnedValue = R_UnwindProtect(callBrowserHook, &bhdata,
1534
                restoreBrowserHookOption, &bhdata,
1535
                NULL);
1536
  }
1537
  else
1538
      R_ReplConsole(rho, savestack, browselevel + 1);
1539
#else
1540
0
  R_ReplConsole(rho, savestack, browselevel + 1);
1541
0
#endif
1542
0
  endcontext(&thiscontext);
1543
0
    }
1544
0
    endcontext(&returncontext);
1545
1546
    /* Reset the interpreter state. */
1547
1548
0
    R_CurrentExpr = topExp;
1549
0
    UNPROTECT(1);
1550
0
    R_PPStackTop = savestack;
1551
0
    UNPROTECT(1);
1552
0
    R_CurrentExpr = topExp;
1553
0
    R_ToplevelContext = saveToplevelContext;
1554
0
    R_GlobalContext = saveGlobalContext;
1555
0
    return R_ReturnedValue;
1556
0
}
1557
1558
void R_dot_Last(void)
1559
0
{
1560
0
    SEXP cmd;
1561
1562
    /* Run the .Last function. */
1563
    /* Errors here should kick us back into the repl. */
1564
1565
0
    R_GlobalContext = R_ToplevelContext = R_SessionContext = &R_Toplevel;
1566
0
    PROTECT(cmd = install(".Last"));
1567
0
    R_CurrentExpr = R_findVar(cmd, R_GlobalEnv);
1568
0
    if (R_CurrentExpr != R_UnboundValue && TYPEOF(R_CurrentExpr) == CLOSXP) {
1569
0
  PROTECT(R_CurrentExpr = lang1(cmd));
1570
0
  R_CurrentExpr = eval(R_CurrentExpr, R_GlobalEnv);
1571
0
  UNPROTECT(1);
1572
0
    }
1573
0
    UNPROTECT(1);
1574
0
    PROTECT(cmd = install(".Last.sys"));
1575
0
    R_CurrentExpr = R_findVar(cmd, R_BaseNamespace);
1576
0
    if (R_CurrentExpr != R_UnboundValue && TYPEOF(R_CurrentExpr) == CLOSXP) {
1577
0
  PROTECT(R_CurrentExpr = lang1(cmd));
1578
0
  R_CurrentExpr = eval(R_CurrentExpr, R_BaseEnv);
1579
0
  UNPROTECT(1);
1580
0
    }
1581
0
    UNPROTECT(1);
1582
0
}
1583
1584
attribute_hidden SEXP do_quit(SEXP call, SEXP op, SEXP args, SEXP rho)
1585
0
{
1586
0
    const char *tmp;
1587
0
    SA_TYPE ask=SA_DEFAULT;
1588
0
    int status, runLast;
1589
1590
0
    checkArity(op, args);
1591
    /* if there are any browser contexts active don't quit */
1592
0
    if(countContexts(CTXT_BROWSER, 1)) {
1593
0
  warning(_("cannot quit from browser"));
1594
0
  return R_NilValue;
1595
0
    }
1596
0
    if( !isString(CAR(args)) )
1597
0
  error(_("one of \"yes\", \"no\", \"ask\" or \"default\" expected."));
1598
0
    tmp = CHAR(STRING_ELT(CAR(args), 0)); /* ASCII */
1599
0
    if( !strcmp(tmp, "ask") ) {
1600
0
  ask = SA_SAVEASK;
1601
0
  if(!R_Interactive)
1602
0
      warning(_("save=\"ask\" in non-interactive use: command-line default will be used"));
1603
0
    } else if( !strcmp(tmp, "no") )
1604
0
  ask = SA_NOSAVE;
1605
0
    else if( !strcmp(tmp, "yes") )
1606
0
  ask = SA_SAVE;
1607
0
    else if( !strcmp(tmp, "default") )
1608
0
  ask = SA_DEFAULT;
1609
0
    else
1610
0
  error(_("unrecognized value of 'save'"));
1611
0
    status = asInteger(CADR(args));
1612
0
    if (status == NA_INTEGER) {
1613
0
  warning(_("invalid 'status', 0 assumed"));
1614
0
  status = 0;
1615
0
    }
1616
0
    runLast = asLogical(CADDR(args));
1617
0
    if (runLast == NA_LOGICAL) {
1618
0
  warning(_("invalid 'runLast', FALSE assumed"));
1619
0
  runLast = 0;
1620
0
    }
1621
    /* run the .Last function. If it gives an error, will drop back to main
1622
       loop. */
1623
0
    R_CleanUp(ask, status, runLast);
1624
0
    exit(0);
1625
    /*NOTREACHED*/
1626
0
}
1627
1628
1629
#include <R_ext/Callbacks.h>
1630
1631
static R_ToplevelCallbackEl *Rf_ToplevelTaskHandlers = NULL;
1632
1633
  /* The handler currently running or NULL. */
1634
static R_ToplevelCallbackEl *Rf_CurrentToplevelHandler = NULL;
1635
1636
  /* A running handler attempted to remove itself from Rf_ToplevelTaskHandlers,
1637
     do it after it finishes. */
1638
static Rboolean Rf_DoRemoveCurrentToplevelHandler = FALSE;
1639
1640
  /* A handler has been removed from the Rf_ToplevelTaskHandlers. */
1641
static Rboolean Rf_RemovedToplevelHandlers = FALSE;
1642
1643
  /* Flag to ensure that the top-level handlers aren't called recursively.
1644
     Simple state to indicate that they are currently being run. */
1645
static Rboolean Rf_RunningToplevelHandlers = FALSE;
1646
1647
/**
1648
  This is the C-level entry point for registering a handler
1649
  that is to be called when each top-level task completes.
1650
1651
  Perhaps we need names to make removing them handlers easier
1652
  since they could be more identified by an invariant (rather than
1653
  position).
1654
 */
1655
//attribute_hidden
1656
R_ToplevelCallbackEl *
1657
Rf_addTaskCallback(R_ToplevelCallback cb, void *data,
1658
       void (*finalizer)(void *), const char *name, int *pos)
1659
0
{
1660
0
    int which;
1661
0
    R_ToplevelCallbackEl *el;
1662
0
    el = (R_ToplevelCallbackEl *) malloc(sizeof(R_ToplevelCallbackEl));
1663
0
    if(!el)
1664
0
  error(_("cannot allocate space for toplevel callback element"));
1665
1666
0
    el->data = data;
1667
0
    el->cb = cb;
1668
0
    el->next = NULL;
1669
0
    el->finalizer = finalizer;
1670
1671
0
    if(Rf_ToplevelTaskHandlers == NULL) {
1672
0
  Rf_ToplevelTaskHandlers = el;
1673
0
  which = 0;
1674
0
    } else {
1675
0
  R_ToplevelCallbackEl *tmp;
1676
0
  tmp = Rf_ToplevelTaskHandlers;
1677
0
  which = 1;
1678
0
  while(tmp->next) {
1679
0
      which++;
1680
0
      tmp = tmp->next;
1681
0
  }
1682
0
  tmp->next = el;
1683
0
    }
1684
1685
0
    if(!name) {
1686
0
  char buf[20];
1687
0
  snprintf(buf, 20, "%d", which+1);
1688
0
  el->name = Rstrdup(buf);
1689
0
    } else
1690
0
  el->name = Rstrdup(name);
1691
1692
0
    if(pos)
1693
0
  *pos = which;
1694
1695
0
    return(el);
1696
0
}
1697
1698
static void removeToplevelHandler(R_ToplevelCallbackEl *e)
1699
0
{
1700
0
    if (Rf_CurrentToplevelHandler == e)
1701
0
  Rf_DoRemoveCurrentToplevelHandler = TRUE; /* postpone */
1702
0
    else {
1703
0
  Rf_RemovedToplevelHandlers = TRUE;
1704
0
  if(e->finalizer)
1705
0
      e->finalizer(e->data);
1706
0
  free(e->name);
1707
0
  free(e);
1708
0
    }
1709
0
}
1710
1711
//attribute_hidden
1712
Rboolean
1713
Rf_removeTaskCallbackByName(const char *name)
1714
0
{
1715
0
    R_ToplevelCallbackEl *el = Rf_ToplevelTaskHandlers, *prev = NULL;
1716
0
    Rboolean status = TRUE;
1717
1718
0
    if(!Rf_ToplevelTaskHandlers) {
1719
0
  return(FALSE); /* error("there are no task callbacks registered"); */
1720
0
    }
1721
1722
0
    while(el) {
1723
0
  if(strcmp(el->name, name) == 0) {
1724
0
      if(prev == NULL) {
1725
0
    Rf_ToplevelTaskHandlers = el->next;
1726
0
      } else {
1727
0
    prev->next = el->next;
1728
0
      }
1729
0
      break;
1730
0
  }
1731
0
  prev = el;
1732
0
  el = el->next;
1733
0
    }
1734
0
    if(el)
1735
0
  removeToplevelHandler(el);
1736
0
    else
1737
0
  status = FALSE;
1738
1739
0
    return(status);
1740
0
}
1741
1742
/**
1743
  Remove the top-level task handler/callback identified by
1744
  its position in the list of callbacks.
1745
 */
1746
//attribute_hidden
1747
Rboolean
1748
Rf_removeTaskCallbackByIndex(int id)
1749
0
{
1750
0
    R_ToplevelCallbackEl *el = Rf_ToplevelTaskHandlers, *tmp = NULL;
1751
0
    Rboolean status = TRUE;
1752
1753
0
    if(id < 0)
1754
0
  error(_("negative index passed to R_removeTaskCallbackByIndex"));
1755
1756
0
    if(Rf_ToplevelTaskHandlers) {
1757
0
  if(id == 0) {
1758
0
      tmp = Rf_ToplevelTaskHandlers;
1759
0
      Rf_ToplevelTaskHandlers = Rf_ToplevelTaskHandlers->next;
1760
0
  } else {
1761
0
      int i = 0;
1762
0
      while(el && i < (id-1)) {
1763
0
    el = el->next;
1764
0
    i++;
1765
0
      }
1766
1767
0
      if(i == (id -1) && el) {
1768
0
    tmp = el->next;
1769
0
    el->next = (tmp ? tmp->next : NULL);
1770
0
      }
1771
0
  }
1772
0
    }
1773
0
    if(tmp)
1774
0
  removeToplevelHandler(tmp);
1775
0
    else
1776
0
  status = FALSE;
1777
1778
0
    return(status);
1779
0
}
1780
1781
1782
/**
1783
  R-level entry point to remove an entry from the
1784
  list of top-level callbacks. 'which' should be an
1785
  integer and give us the 0-based index of the element
1786
  to be removed from the list.
1787
1788
  @see Rf_RemoveToplevelCallbackByIndex(int)
1789
 */
1790
attribute_hidden SEXP
1791
R_removeTaskCallback(SEXP which)
1792
0
{
1793
0
    int id;
1794
0
    Rboolean val;
1795
1796
0
    if(TYPEOF(which) == STRSXP) {
1797
0
  if (LENGTH(which) == 0)
1798
0
      val = FALSE;
1799
0
  else
1800
0
      val = Rf_removeTaskCallbackByName(CHAR(STRING_ELT(which, 0)));
1801
0
    } else {
1802
0
  id = asInteger(which);
1803
0
  if (id != NA_INTEGER) val = Rf_removeTaskCallbackByIndex(id - 1);
1804
0
  else val = FALSE;
1805
0
    }
1806
0
    return ScalarLogical(val);
1807
0
}
1808
1809
attribute_hidden SEXP
1810
R_getTaskCallbackNames(void)
1811
0
{
1812
0
    SEXP ans;
1813
0
    R_ToplevelCallbackEl *el;
1814
0
    int n = 0;
1815
1816
0
    el = Rf_ToplevelTaskHandlers;
1817
0
    while(el) {
1818
0
  n++;
1819
0
  el = el->next;
1820
0
    }
1821
0
    PROTECT(ans = allocVector(STRSXP, n));
1822
0
    n = 0;
1823
0
    el = Rf_ToplevelTaskHandlers;
1824
0
    while(el) {
1825
0
  SET_STRING_ELT(ans, n, mkChar(el->name));
1826
0
  n++;
1827
0
  el = el->next;
1828
0
    }
1829
0
    UNPROTECT(1);
1830
0
    return(ans);
1831
0
}
1832
1833
/**
1834
  Invokes each of the different handlers giving the
1835
  top-level expression that was just evaluated,
1836
  the resulting value from the evaluation, and
1837
  whether the task succeeded. The last may be useful
1838
  if a handler is also called as part of the error handling.
1839
  We also have information about whether the result was printed or not.
1840
  We currently do not pass this to the handler.
1841
 */
1842
1843
/* This is not used in R and in no header */
1844
void
1845
Rf_callToplevelHandlers(SEXP expr, SEXP value, Rboolean succeeded,
1846
      Rboolean visible)
1847
0
{
1848
0
    R_ToplevelCallbackEl *h, *prev = NULL;
1849
0
    Rboolean again;
1850
1851
0
    if(Rf_RunningToplevelHandlers == TRUE)
1852
0
  return;
1853
1854
0
    h = Rf_ToplevelTaskHandlers;
1855
0
    Rf_RunningToplevelHandlers = TRUE;
1856
0
    while(h) {
1857
0
  Rf_RemovedToplevelHandlers = FALSE;
1858
0
  Rf_DoRemoveCurrentToplevelHandler = FALSE;
1859
0
  Rf_CurrentToplevelHandler = h;
1860
0
  again = (h->cb)(expr, value, succeeded, visible, h->data);
1861
0
  Rf_CurrentToplevelHandler = NULL;
1862
1863
0
  if (Rf_DoRemoveCurrentToplevelHandler) {
1864
      /* the handler attempted to remove itself, PR#18508 */
1865
0
      Rf_DoRemoveCurrentToplevelHandler = FALSE;
1866
0
      again = FALSE;
1867
0
  }
1868
0
  if (Rf_RemovedToplevelHandlers) {
1869
      /* some handlers were removed, but not "h" -> recompute "prev" */
1870
0
      prev = NULL;
1871
0
      R_ToplevelCallbackEl *h2 = Rf_ToplevelTaskHandlers;
1872
0
      while(h2 != h) {
1873
0
    prev = h2;
1874
0
    h2 = h2->next;
1875
0
    if (!h2)
1876
0
        R_Suicide("list of toplevel callbacks was corrupted");
1877
0
      }
1878
0
  }
1879
1880
0
  if(R_CollectWarnings) {
1881
0
      REprintf(_("warning messages from top-level task callback '%s'\n"),
1882
0
         h->name);
1883
0
      PrintWarnings();
1884
0
  }
1885
0
  if(again) {
1886
0
      prev = h;
1887
0
      h = h->next;
1888
0
  } else {
1889
0
      R_ToplevelCallbackEl *tmp;
1890
0
      tmp = h;
1891
0
      if(prev)
1892
0
    prev->next = h->next;
1893
0
      h = h->next;
1894
0
      if(tmp == Rf_ToplevelTaskHandlers)
1895
0
    Rf_ToplevelTaskHandlers = h;
1896
0
      if(tmp->finalizer)
1897
0
    tmp->finalizer(tmp->data);
1898
0
      free(tmp->name);
1899
0
      free(tmp);
1900
0
  }
1901
0
    }
1902
1903
0
    Rf_RunningToplevelHandlers = FALSE;
1904
0
}
1905
1906
1907
static void defineVarInc(SEXP sym, SEXP val, SEXP rho)
1908
0
{
1909
0
    defineVar(sym, val, rho);
1910
0
    INCREMENT_NAMED(val); /* in case this is used in a NAMED build */
1911
0
}
1912
1913
attribute_hidden Rboolean
1914
R_taskCallbackRoutine(SEXP expr, SEXP value, Rboolean succeeded,
1915
          Rboolean visible, void *userData)
1916
0
{
1917
    /* install some symbols */
1918
0
    static SEXP R_cbSym = NULL;
1919
0
    static SEXP R_exprSym = NULL;
1920
0
    static SEXP R_valueSym = NULL;
1921
0
    static SEXP R_succeededSym = NULL;
1922
0
    static SEXP R_visibleSym = NULL;
1923
0
    static SEXP R_dataSym = NULL;
1924
0
    if (R_cbSym == NULL) {
1925
0
  R_cbSym = install("cb");
1926
0
  R_exprSym = install("expr");
1927
0
  R_valueSym = install("value");
1928
0
  R_succeededSym = install("succeeded");
1929
0
  R_visibleSym = install("visible");
1930
0
  R_dataSym = install("data");
1931
0
    }
1932
1933
0
    SEXP f = (SEXP) userData;
1934
0
    SEXP e, val, cur, rho;
1935
0
    int errorOccurred;
1936
0
    Rboolean again, useData = (Rboolean)LOGICAL(VECTOR_ELT(f, 2))[0];
1937
1938
    /* create an environment with bindings for the function and arguments */
1939
0
    PROTECT(rho = NewEnvironment(R_NilValue, R_NilValue, R_GlobalEnv));
1940
0
    defineVarInc(R_cbSym, VECTOR_ELT(f, 0), rho);
1941
0
    defineVarInc(R_exprSym, expr, rho);
1942
0
    defineVarInc(R_valueSym, value, rho);
1943
0
    defineVarInc(R_succeededSym, ScalarLogical(succeeded), rho);
1944
0
    defineVarInc(R_visibleSym, ScalarLogical(visible), rho);
1945
0
    if(useData)
1946
0
  defineVarInc(R_dataSym, VECTOR_ELT(f, 1), rho);
1947
1948
    /* create the call; these could be saved and re-used */
1949
0
    PROTECT(e = allocVector(LANGSXP, 5 + useData));
1950
0
    SETCAR(e, R_cbSym); cur = CDR(e);
1951
0
    SETCAR(cur, R_exprSym); cur = CDR(cur);
1952
0
    SETCAR(cur, R_valueSym); cur = CDR(cur);
1953
0
    SETCAR(cur, R_succeededSym); cur = CDR(cur);
1954
0
    SETCAR(cur, R_visibleSym); cur = CDR(cur);
1955
0
    if(useData)
1956
0
  SETCAR(cur, R_dataSym);
1957
1958
0
    val = R_tryEval(e, rho, &errorOccurred);
1959
0
    PROTECT(val);
1960
1961
    /* clear the environment to reduce reference counts */
1962
0
    defineVar(R_cbSym, R_NilValue, rho);
1963
0
    defineVar(R_exprSym, R_NilValue, rho);
1964
0
    defineVar(R_valueSym, R_NilValue, rho);
1965
0
    defineVar(R_succeededSym, R_NilValue, rho);
1966
0
    defineVar(R_visibleSym, R_NilValue, rho);
1967
0
    if(useData)
1968
0
  defineVar(R_dataSym, R_NilValue, rho);
1969
1970
0
    if(!errorOccurred) {
1971
0
  if(TYPEOF(val) != LGLSXP) {
1972
      /* It would be nice to identify the function. */
1973
0
      warning(_("top-level task callback did not return a logical value"));
1974
0
  }
1975
0
  again = (Rboolean) asLogical(val);
1976
0
    } else {
1977
  /* warning("error occurred in top-level task callback\n"); */
1978
0
  again = FALSE;
1979
0
    }
1980
1981
0
    UNPROTECT(3); /* rho, e, val */
1982
1983
0
    return(again);
1984
0
}
1985
1986
static void releaseObjectFinalizer(void *data)
1987
0
{
1988
0
    R_ReleaseObject((SEXP)data);
1989
0
}
1990
1991
attribute_hidden SEXP
1992
R_addTaskCallback(SEXP f, SEXP data, SEXP useData, SEXP name)
1993
0
{
1994
0
    SEXP internalData;
1995
0
    SEXP index;
1996
0
    R_ToplevelCallbackEl *el;
1997
0
    const char *tmpName = NULL;
1998
1999
0
    internalData = allocVector(VECSXP, 3);
2000
0
    R_PreserveObject(internalData);
2001
0
    SET_VECTOR_ELT(internalData, 0, f);
2002
0
    SET_VECTOR_ELT(internalData, 1, data);
2003
0
    SET_VECTOR_ELT(internalData, 2, useData);
2004
2005
0
    if(length(name))
2006
0
  tmpName = CHAR(STRING_ELT(name, 0));
2007
2008
0
    PROTECT(index = allocVector(INTSXP, 1));
2009
0
    el = Rf_addTaskCallback(R_taskCallbackRoutine,  internalData,
2010
0
          releaseObjectFinalizer, tmpName,
2011
0
          INTEGER(index));
2012
2013
0
    if(length(name) == 0) {
2014
0
  PROTECT(name = mkString(el->name));
2015
0
  setAttrib(index, R_NamesSymbol, name);
2016
0
  UNPROTECT(1);
2017
0
    } else {
2018
0
  setAttrib(index, R_NamesSymbol, name);
2019
0
    }
2020
2021
0
    UNPROTECT(1);
2022
0
    return(index);
2023
0
}
2024
2025
#undef __MAIN__
2026
2027
#ifndef Win32
2028
/* this is here solely to pull in xxxpr.o */
2029
# include <R_ext/RS.h>
2030
# if defined FC_LEN_T
2031
# include <stddef.h>
2032
void F77_SUB(rwarnc)(char *msg, int *nchar, FC_LEN_T msg_len);
2033
attribute_hidden void dummy54321(void)
2034
0
{
2035
0
    int nc = 5;
2036
0
    F77_CALL(rwarnc)("dummy", &nc, (FC_LEN_T) 5);
2037
0
}
2038
# else
2039
void F77_SUB(rwarnc)(char *msg, int *nchar);
2040
attribute_hidden void dummy54321(void)
2041
{
2042
    int nc = 5;
2043
    F77_CALL(rwarnc)("dummy", &nc);
2044
}
2045
# endif
2046
#endif