The R Project SVN R

Rev

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

Rev Author Line No. Line
2 r 1
/*
2440 maechler 2
 *  R : A Computer Language for Statistical Data Analysis
2 r 3
 *  Copyright (C) 1995, 1996  Robert Gentleman and Ross Ihaka
17742 ripley 4
 *  Copyright (C) 1997--2002  The R Development Core Team.
2 r 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
17
 *  along with this program; if not, write to the Free Software
5458 ripley 18
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
2 r 19
 */
20
 
5187 hornik 21
#ifdef HAVE_CONFIG_H
7701 hornik 22
#include <config.h>
5187 hornik 23
#endif
24
 
25478 iacus 25
#ifdef HAVE_AQUA
26
extern void R_ProcessEvents(void);
27
#endif
28
 
29
 
13305 ripley 30
#include <Defn.h>
11046 maechler 31
/* -> Errormsg.h */
13305 ripley 32
#include <Startup.h> /* rather cleanup ..*/
33
#include <Rconnections.h>
11046 maechler 34
 
20106 ripley 35
#ifndef min
36
#define min(a, b) (a<b?a:b)
37
#endif
38
 
7879 ripley 39
/* limit on call length at which errorcall/warningcall is split over
40
   two lines */
41
#define LONGCALL 30
2 r 42
 
8004 maechler 43
/*
6199 rgentlem 44
Different values of inError are used to indicate different places
45
in the error handling.
46
*/
8004 maechler 47
static int inError = 0;
4230 rgentlem 48
static int inWarning = 0;
25367 luke 49
static int inPrintWarnings = 0;
2 r 50
 
25470 luke 51
static void try_jump_to_restart(void);
25370 luke 52
static void jump_to_top_ex(Rboolean, Rboolean, Rboolean, Rboolean, Rboolean);
26354 luke 53
static void signalInterrupt(void);
25368 luke 54
 
6098 pd 55
/* Interface / Calling Hierarchy :
56
 
25472 luke 57
  R__stop()   -> do_error ->   errorcall --> jump_to_top_ex
8004 maechler 58
			 /
59
		    error
6098 pd 60
 
61
  R__warning()-> do_warning   -> warningcall -> if(warn >= 2) errorcall
62
			     /
63
		    warning /
64
 
14442 luke 65
  ErrorMessage()-> errorcall   (but with message from ErrorDB[])
6098 pd 66
 
14443 luke 67
  WarningMessage()-> warningcall (but with message from WarningDB[]).
6098 pd 68
*/
69
 
70
 
25212 luke 71
void R_CheckUserInterrupt(void)
72
{
25224 luke 73
    /* This is the point where GUI systems need to do enough event
74
       processing to determine whether there is a user interrupt event
75
       pending.  Need to be careful not to do too much event
76
       processing though: if event handlers written in R are allowed
77
       to run at this point then we end up with concurrent R
78
       evaluations and that can cause problems until we have proper
79
       concurrency support. LT */
25514 iacus 80
#if  ( defined(HAVE_AQUA) || defined(Win32) ) 
25212 luke 81
    R_ProcessEvents();
82
#else
25497 luke 83
    if (R_interrupts_pending)
25212 luke 84
	onintr();
85
#endif /* Win32 */
86
}
87
 
2 r 88
void onintr()
89
{
25497 luke 90
    if (R_interrupts_suspended) {
91
	R_interrupts_pending = 1;
92
	return;
93
    }
94
    else R_interrupts_pending = 0;
26354 luke 95
 
96
    signalInterrupt();
97
 
1839 ihaka 98
    REprintf("\n");
25370 luke 99
    /* Attempt to run user error option, save a traceback, show
100
       warnings, and reset console; also stop at restart (try/browser)
101
       frames.  Not clear this is what we really want, but this
102
       preserves current behavior */
103
    jump_to_top_ex(TRUE, TRUE, TRUE, TRUE, FALSE);
2 r 104
}
105
 
8422 tlumley 106
/* SIGUSR1: save and quit
107
   SIGUSR2: save and quit, don't run .Last or on.exit().
108
*/
14478 luke 109
 
8422 tlumley 110
void onsigusr1()
111
{
25221 luke 112
    if (R_interrupts_suspended) {
113
	/**** ought to save signal and handle after suspend */
114
	REprintf("interrupts suspended; signal ignored");
115
	return;
116
    }
117
 
8422 tlumley 118
    inError = 1;
119
 
25358 luke 120
    if( R_CollectWarnings )
8422 tlumley 121
	PrintWarnings();
122
 
123
    R_ResetConsole();
124
    R_FlushConsole();
125
    R_ClearerrConsole();
126
    R_ParseError = 0;
14478 luke 127
 
25470 luke 128
    /* Bail out if there is a browser/try on the stack--do we really
14478 luke 129
       want this? */
25470 luke 130
    try_jump_to_restart();
14478 luke 131
 
132
    /* Run all onexit/cend code on the stack (without stopping at
133
       intervening CTXT_TOPLEVEL's.  Since intervening CTXT_TOPLEVEL's
134
       get used by what are conceptually concurrent computations, this
135
       is a bit like telling all active threads to terminate and clean
136
       up on the way out. */
137
    R_run_onexits(NULL);
138
 
14443 luke 139
    R_CleanUp(SA_SAVE, 2, 1); /* quit, save,  .Last, status=2 */
8422 tlumley 140
}
141
 
142
 
143
void onsigusr2()
144
{
145
    inError = 1;
8892 maechler 146
 
25221 luke 147
    if (R_interrupts_suspended) {
148
	/**** ought to save signal and handle after suspend */
149
	REprintf("interrupts suspended; signal ignored");
150
	return;
151
    }
152
 
25358 luke 153
    if( R_CollectWarnings )
8422 tlumley 154
	PrintWarnings();
8892 maechler 155
 
8422 tlumley 156
    R_ResetConsole();
157
    R_FlushConsole();
158
    R_ClearerrConsole();
159
    R_ParseError = 0;
160
    R_CleanUp(SA_SAVE, 0, 0);
161
}
162
 
163
 
4179 rgentlem 164
static void setupwarnings(void)
2 r 165
{
4179 rgentlem 166
    R_Warnings = allocVector(VECSXP, 50);
167
    setAttrib(R_Warnings, R_NamesSymbol, allocVector(STRSXP, 50));
168
}
169
 
14439 luke 170
/* Rvsnprintf: like vsnprintf, but guaranteed to null-terminate. */
171
static int Rvsnprintf(char *buf, size_t size, const char  *format, va_list ap)
172
{
173
    int val;
174
    val = vsnprintf(buf, size, format, ap);
175
    buf[size-1] = '\0';
176
    return val;
177
}
178
 
4179 rgentlem 179
#define BUFSIZE 8192
180
void warning(const char *format, ...)
181
{
5502 ripley 182
    char buf[BUFSIZE], *p;
4179 rgentlem 183
 
1839 ihaka 184
    va_list(ap);
185
    va_start(ap, format);
20106 ripley 186
    Rvsnprintf(buf, min(BUFSIZE, R_WarnLength), format, ap);
1839 ihaka 187
    va_end(ap);
5502 ripley 188
    p = buf + strlen(buf) - 1;
189
    if(strlen(buf) > 0 && *p == '\n') *p = '\0';
4179 rgentlem 190
    warningcall(R_NilValue, buf);
2 r 191
}
4165 rgentlem 192
 
14570 luke 193
/* temporary hook to allow experimenting with alternate warning mechanisms */
194
static void (*R_WarningHook)(SEXP, char *) = NULL;
195
 
25523 luke 196
#ifdef NEW_CONDITION_HANDLING
197
/* declarations for internal condition handling */
198
 
25526 luke 199
static void vsignalError(SEXP call, const char *format, va_list ap);
25523 luke 200
static void vsignalWarning(SEXP call, const char *format, va_list ap);
201
static void invokeRestart(SEXP, SEXP);
202
#endif
203
 
25352 luke 204
static void reset_inWarning(void *data)
205
{
206
    inWarning = 0;
207
}
208
 
25523 luke 209
static void vwarningcall_dflt(SEXP call, const char *format, va_list ap)
2 r 210
{
12976 pd 211
    int w;
4165 rgentlem 212
    SEXP names, s;
4179 rgentlem 213
    char *dcall, buf[BUFSIZE];
4165 rgentlem 214
    RCNTXT *cptr;
25352 luke 215
    RCNTXT cntxt;
4165 rgentlem 216
 
25368 luke 217
    if (inWarning)
218
	return;
219
 
4247 rgentlem 220
    s = GetOption(install("warning.expression"), R_NilValue);
221
    if( s!= R_NilValue ) {
8004 maechler 222
	if( !isLanguage(s) &&  ! isExpression(s) )
223
	    error("invalid option \"warning.expression\"");
224
	cptr = R_GlobalContext;
225
	while ( !(cptr->callflag & CTXT_FUNCTION) && cptr->callflag )
226
	    cptr = cptr->nextcontext;
6199 rgentlem 227
	eval(s, cptr->cloenv);
8004 maechler 228
	return;
4247 rgentlem 229
    }
230
 
4165 rgentlem 231
    w = asInteger(GetOption(install("warn"), R_NilValue));
4230 rgentlem 232
 
4179 rgentlem 233
    if( w == NA_INTEGER ) /* set to a sensible value */
234
	w = 0;
4230 rgentlem 235
 
12976 pd 236
    if(w < 0 || inWarning || inError)  {/* ignore if w<0 or already in here*/
8004 maechler 237
	return;
4230 rgentlem 238
    }
25352 luke 239
 
240
    /* set up a context which will restore inWarning if there is an exit */
241
    begincontext(&cntxt, CTXT_CCODE, R_NilValue, R_NilValue, R_NilValue,
242
		 R_NilValue, R_NilValue);
243
    cntxt.cend = &reset_inWarning;
244
 
4230 rgentlem 245
    inWarning = 1;
246
 
12976 pd 247
    if(w >= 2) { /* make it an error */
20106 ripley 248
	Rvsnprintf(buf, min(BUFSIZE, R_WarnLength), format, ap);
19761 ripley 249
	inWarning = 0; /* PR#1570 */
8004 maechler 250
	errorcall(call, "(converted from warning) %s", buf);
4165 rgentlem 251
    }
12976 pd 252
    else if(w == 1) {	/* print as they happen */
8004 maechler 253
	if( call != R_NilValue ) {
10172 luke 254
	    dcall = CHAR(STRING_ELT(deparse1(call, 0), 0));
8004 maechler 255
	    REprintf("Warning in %s : ", dcall);
256
	    if (strlen(dcall) > LONGCALL) REprintf("\n	 ");
257
	}
258
	else
259
	    REprintf("Warning: ");
20106 ripley 260
	Rvsnprintf(buf, min(BUFSIZE, R_WarnLength), format, ap);
261
	REprintf("%s\n", buf);
4165 rgentlem 262
    }
12976 pd 263
    else if(w == 0) {	/* collect them */
6191 maechler 264
	if(!R_CollectWarnings)
8004 maechler 265
	    setupwarnings();
6191 maechler 266
	if( R_CollectWarnings > 49 )
4179 rgentlem 267
	    return;
10172 luke 268
	SET_VECTOR_ELT(R_Warnings, R_CollectWarnings, call);
20106 ripley 269
	Rvsnprintf(buf, min(BUFSIZE, R_WarnLength), format, ap);
4165 rgentlem 270
	names = CAR(ATTRIB(R_Warnings));
10172 luke 271
	SET_STRING_ELT(names, R_CollectWarnings++, mkChar(buf));
6191 maechler 272
    }
6098 pd 273
    /* else:  w <= -1 */
25352 luke 274
    endcontext(&cntxt);
4230 rgentlem 275
    inWarning = 0;
2 r 276
}
277
 
25523 luke 278
static void warningcall_dflt(SEXP call, const char *format,...)
279
{
280
    va_list(ap);
281
 
282
    va_start(ap, format);
283
    vwarningcall_dflt(call, format, ap);
284
    va_end(ap);
285
}
286
 
287
void warningcall(SEXP call, const char *format, ...)
288
{
289
    va_list(ap);
290
#ifdef NEW_CONDITION_HANDLING
291
    va_start(ap, format);
292
    vsignalWarning(call, format, ap);
293
    va_end(ap);
294
#else
295
    if (R_WarningHook != NULL) {
296
	char buf[BUFSIZE];
297
	va_start(ap, format);
298
	Rvsnprintf(buf, min(BUFSIZE, R_WarnLength), format, ap);
299
	va_end(ap);
300
	R_WarningHook(call, buf);
301
	return;
302
    }
303
 
304
    va_start(ap, format);
305
    vwarningcall_dflt(call, format, ap);
306
    va_end(ap);
307
#endif
308
}
309
 
25358 luke 310
static void cleanup_PrintWarnings(void *data)
311
{
25367 luke 312
    if (R_CollectWarnings) {
313
	R_CollectWarnings = 0;
314
	R_Warnings = R_NilValue;
25358 luke 315
	REprintf("Lost warning messages\n");
25367 luke 316
    }
317
    inPrintWarnings = 0;
25358 luke 318
}
319
 
6191 maechler 320
void PrintWarnings(void)
4165 rgentlem 321
{
322
    int i;
323
    SEXP names, s, t;
25352 luke 324
    RCNTXT cntxt;
4165 rgentlem 325
 
25367 luke 326
    if (R_CollectWarnings == 0)
327
	return;
328
    else if (inPrintWarnings) {
329
	if (R_CollectWarnings) {
330
	    R_CollectWarnings = 0;
331
	    R_Warnings = R_NilValue;
332
	    REprintf("Lost warning messages\n");
333
	}
334
	return;
335
    }
336
 
337
    /* set up a context which will restore inPrintWarnings if there is
338
       an exit */
25352 luke 339
    begincontext(&cntxt, CTXT_CCODE, R_NilValue, R_NilValue, R_NilValue,
340
		 R_NilValue, R_NilValue);
25358 luke 341
    cntxt.cend = &cleanup_PrintWarnings;
25352 luke 342
 
25367 luke 343
    inPrintWarnings = 1;
4165 rgentlem 344
    if( R_CollectWarnings == 1 ) {
345
	REprintf("Warning message: \n");
346
	names = CAR(ATTRIB(R_Warnings));
10172 luke 347
	if( VECTOR_ELT(R_Warnings, 0) == R_NilValue )
348
	   REprintf("%s \n", CHAR(STRING_ELT(names, 0)));
8004 maechler 349
	else
10172 luke 350
	   REprintf("%s in: %s \n", CHAR(STRING_ELT(names, 0)),
351
		CHAR(STRING_ELT(deparse1(VECTOR_ELT(R_Warnings, 0),0), 0)));
4165 rgentlem 352
    }
353
    else if( R_CollectWarnings <= 10 ) {
8004 maechler 354
	REprintf("Warning messages: \n");
4165 rgentlem 355
	names = CAR(ATTRIB(R_Warnings));
356
	for(i=0; i<R_CollectWarnings; i++) {
10172 luke 357
	    if( STRING_ELT(R_Warnings, i) == R_NilValue )
358
	       REprintf("%d: %s \n",i+1, CHAR(STRING_ELT(names, i)));
8004 maechler 359
	    else
10172 luke 360
	       REprintf("%d: %s in: %s \n", i+1, CHAR(STRING_ELT(names, i)),
361
		   CHAR(STRING_ELT(deparse1(VECTOR_ELT(R_Warnings,i), 0), 0)));
4165 rgentlem 362
	}
363
    }
364
    else {
8315 ripley 365
	if (R_CollectWarnings < 50)
366
	    REprintf("There were %d warnings (use warnings() to see them)\n",
367
		     R_CollectWarnings);
368
	else
369
	    REprintf("There were 50 or more warnings (use warnings() to see the first 50)\n");
4165 rgentlem 370
    }
371
    /* now truncate and install last.warning */
372
    PROTECT(s = allocVector(VECSXP, R_CollectWarnings));
373
    PROTECT(t = allocVector(STRSXP, R_CollectWarnings));
374
    names = CAR(ATTRIB(R_Warnings));
375
    for(i=0; i<R_CollectWarnings; i++) {
10172 luke 376
	SET_VECTOR_ELT(s, i, VECTOR_ELT(R_Warnings, i));
377
	SET_VECTOR_ELT(t, i, VECTOR_ELT(names, i));
4165 rgentlem 378
    }
379
    setAttrib(s, R_NamesSymbol, t);
380
    defineVar(install("last.warning"), s, R_GlobalEnv);
381
    UNPROTECT(2);
25352 luke 382
 
383
    endcontext(&cntxt);
384
 
25367 luke 385
    inPrintWarnings = 0;
7879 ripley 386
    R_CollectWarnings = 0;
387
    R_Warnings = R_NilValue;
4165 rgentlem 388
    return;
389
}
390
 
8103 ripley 391
static char errbuf[BUFSIZE];
4165 rgentlem 392
 
14570 luke 393
/* temporary hook to allow experimenting with alternate error mechanisms */
394
static void (*R_ErrorHook)(SEXP, char *) = NULL;
395
 
25352 luke 396
static void restore_inError(void *data)
397
{
398
    int *poldval = data;
399
    inError = *poldval;
400
}
401
 
25523 luke 402
static void verrorcall_dflt(SEXP call, const char *format, va_list ap)
2 r 403
{
25352 luke 404
    RCNTXT cntxt;
8103 ripley 405
    char *p, *dcall;
25352 luke 406
    int oldInError;
8004 maechler 407
 
8892 maechler 408
    if (inError) {
25367 luke 409
	/* fail-safe handler for recursive errors */
14608 luke 410
	if(inError == 3) {
411
	     /* Can REprintf generate an error? If so we should guard for it */
412
	    REprintf("Error during wrapup: ");
413
	    /* this does NOT try to print the call since that could
414
               cause a cascade of error calls */
415
	    Rvsnprintf(errbuf, sizeof(errbuf), format, ap);
416
	    REprintf("%s\n", errbuf);
417
	}
25367 luke 418
	if (R_Warnings != R_NilValue) {
419
	    R_CollectWarnings = 0;
420
	    R_Warnings = R_NilValue;
421
	    REprintf("Lost warning messages\n");
422
	}
25370 luke 423
	jump_to_top_ex(FALSE, FALSE, FALSE, FALSE, FALSE);
6199 rgentlem 424
    }
425
 
25352 luke 426
    /* set up a context to restore inError value on exit */
427
    begincontext(&cntxt, CTXT_CCODE, R_NilValue, R_NilValue, R_NilValue,
428
		 R_NilValue, R_NilValue);
429
    cntxt.cend = &restore_inError;
430
    cntxt.cenddata = &oldInError;
431
    oldInError = inError;
25368 luke 432
    inError = 1;
25352 luke 433
 
8892 maechler 434
    if(call != R_NilValue) {
14439 luke 435
	char *head = "Error in ";
436
	char *mid = " : ";
437
	char *tail = "\n\t";/* <- TAB */
438
	int len = strlen(head) + strlen(mid) + strlen(tail);
439
 
10172 luke 440
	dcall = CHAR(STRING_ELT(deparse1(call, 0), 0));
14439 luke 441
	if (strlen(dcall) + len < BUFSIZE) {
442
	    sprintf(errbuf, "%s%s%s", head, dcall, mid);
443
	    if (strlen(dcall) > LONGCALL) strcat(errbuf, tail);
444
	}
445
	else
446
	    sprintf(errbuf, "Error: ");
4179 rgentlem 447
    }
448
    else
8103 ripley 449
	sprintf(errbuf, "Error: ");
6199 rgentlem 450
 
8103 ripley 451
    p = errbuf + strlen(errbuf);
20106 ripley 452
    Rvsnprintf(p, min(BUFSIZE, R_WarnLength) - strlen(errbuf), format, ap);
8103 ripley 453
    p = errbuf + strlen(errbuf) - 1;
454
    if(*p != '\n') strcat(errbuf, "\n");
455
    if (R_ShowErrorMessages) REprintf("%s", errbuf);
25358 luke 456
 
457
    if( R_ShowErrorMessages && R_CollectWarnings ) {
458
	REprintf("In addition: ");
459
	PrintWarnings();
460
    }
461
 
25370 luke 462
    jump_to_top_ex(TRUE, TRUE, TRUE, TRUE, FALSE);
25352 luke 463
 
464
    /* not reached */
465
    endcontext(&cntxt);
25368 luke 466
    inError = oldInError;
2 r 467
}
468
 
25523 luke 469
static void errorcall_dflt(SEXP call, const char *format,...)
470
{
471
    va_list(ap);
472
 
473
    va_start(ap, format);
474
    verrorcall_dflt(call, format, ap);
475
    va_end(ap);
476
}
477
 
478
void errorcall(SEXP call, const char *format,...)
479
{
480
    va_list(ap);
481
 
482
#ifdef NEW_CONDITION_HANDLING
483
    va_start(ap, format);
25526 luke 484
    vsignalError(call, format, ap);
25523 luke 485
    va_end(ap);
486
#endif
487
 
488
    if (R_ErrorHook != NULL) {
489
	char buf[BUFSIZE];
490
	void (*hook)(SEXP, char *) = R_ErrorHook;
491
	R_ErrorHook = NULL; /* to avoid recursion */
492
	va_start(ap, format);
493
	Rvsnprintf(buf, min(BUFSIZE, R_WarnLength), format, ap);
494
	va_end(ap);
495
	hook(call, buf);
496
    }
497
 
498
    va_start(ap, format);
499
    verrorcall_dflt(call, format, ap);
500
    va_end(ap);
501
}
502
 
8103 ripley 503
SEXP do_geterrmessage(SEXP call, SEXP op, SEXP args, SEXP env)
504
{
505
    SEXP res;
506
 
507
    checkArity(op, args);
508
    PROTECT(res = allocVector(STRSXP, 1));
10172 luke 509
    SET_STRING_ELT(res, 0, mkChar(errbuf));
8892 maechler 510
    UNPROTECT(1);
8103 ripley 511
    return res;
512
}
513
 
2 r 514
void error(const char *format, ...)
515
{
14494 hornik 516
    char buf[BUFSIZE];
6199 rgentlem 517
 
1839 ihaka 518
    va_list(ap);
519
    va_start(ap, format);
20106 ripley 520
    Rvsnprintf(buf, min(BUFSIZE, R_WarnLength), format, ap);
1839 ihaka 521
    va_end(ap);
16986 pd 522
    /* This can be called before R_GlobalContext is defined, so... */
523
    errorcall(R_GlobalContext ?
524
	      R_GlobalContext->call : R_NilValue, "%s", buf);
2 r 525
}
526
 
25470 luke 527
static void try_jump_to_restart(void)
528
{
25523 luke 529
#ifdef NEW_CONDITION_HANDLING
530
    SEXP list;
531
 
532
    for (list = R_RestartStack; list != R_NilValue; list = CDR(list)) {
533
	SEXP restart = CAR(list);
534
	if (TYPEOF(restart) == VECSXP && LENGTH(restart) > 1) {
535
	    SEXP name = VECTOR_ELT(restart, 0);
536
	    if (TYPEOF(name) == STRSXP && LENGTH(name) == 1) {
537
		char *cname = CHAR(STRING_ELT(name, 0));
538
		if (! strcmp(cname, "browser") ||
539
		    ! strcmp(cname, "tryRestart") ||
540
		    ! strcmp(cname, "abort")) /**** move abort eventually? */
541
		    invokeRestart(restart, R_NilValue);
542
	    }
543
	}
544
    }
545
#else
25470 luke 546
    RCNTXT *c;
547
 
548
    for (c = R_GlobalContext; c; c = c->nextcontext) {
549
	if (IS_RESTART_BIT_SET(c->callflag)) {
550
	    inError=0;
551
	    findcontext(CTXT_RESTART, c->cloenv, R_RestartToken);
552
	}
553
	if (c->callflag == CTXT_TOPLEVEL)
554
	    break;
555
    }
25523 luke 556
#endif
25470 luke 557
}
558
 
2 r 559
/* Unwind the call stack in an orderly fashion */
560
/* calling the code installed by on.exit along the way */
11414 rgentlem 561
/* and finally longjmping to the innermost TOPLEVEL context */
2 r 562
 
25368 luke 563
static void jump_to_top_ex(Rboolean traceback,
564
			   Rboolean tryUserHandler,
565
			   Rboolean processWarnings,
25370 luke 566
			   Rboolean resetConsole,
567
			   Rboolean ignoreRestartContexts)
2 r 568
{
25352 luke 569
    RCNTXT cntxt;
25421 luke 570
    SEXP s;
25352 luke 571
    int haveHandler, oldInError;
6098 pd 572
 
25352 luke 573
    /* set up a context to restore inError value on exit */
574
    begincontext(&cntxt, CTXT_CCODE, R_NilValue, R_NilValue, R_NilValue,
575
		 R_NilValue, R_NilValue);
576
    cntxt.cend = &restore_inError;
577
    cntxt.cenddata = &oldInError;
6178 rgentlem 578
 
25352 luke 579
    oldInError = inError;
580
 
25368 luke 581
    haveHandler = FALSE;
25352 luke 582
 
25368 luke 583
    if (tryUserHandler && inError < 3) {
584
	if (! inError)
585
	    inError = 1;
6199 rgentlem 586
 
25353 luke 587
	/*now see if options("error") is set */
588
	s = GetOption(install("error"), R_NilValue);
589
	haveHandler = ( s != R_NilValue );
590
	if (haveHandler) {
591
	    if( !isLanguage(s) &&  ! isExpression(s) )  /* shouldn't happen */
592
		REprintf("invalid option \"error\"\n");
593
	    else {
594
		inError = 3;
595
		if (isLanguage(s))
596
		    eval(s, R_GlobalEnv);
597
		else /* expression */
598
		    {
599
			int i, n = LENGTH(s);
600
			for (i = 0 ; i < n ; i++)
601
			    eval(VECTOR_ELT(s, i), R_GlobalEnv);
602
		    }
25368 luke 603
		inError = oldInError;
25353 luke 604
	    }
605
	}
25368 luke 606
	inError = oldInError;
607
    }
25353 luke 608
 
25368 luke 609
    /* print warnings if there are any left to be printed */
610
    if( processWarnings && R_CollectWarnings )
611
	PrintWarnings();
25358 luke 612
 
25368 luke 613
    /* reset some stuff--not sure (all) this belongs here */
614
    if (resetConsole) {
25353 luke 615
	R_ResetConsole();
616
	R_FlushConsole();
617
	R_ClearerrConsole();
618
	R_ParseError = 0;
6199 rgentlem 619
    }
620
 
25368 luke 621
    /* WARNING: If oldInError > 0 ABSOLUTELY NO ALLOCATION can be
27000 luke 622
       triggered after this point except whatever happens in writing
623
       the traceback and R_run_onexits.  The error could be an out of
624
       memory error and any allocation could result in an
625
       infinite-loop condition. All you can do is reset things and
626
       exit.  */
14478 luke 627
 
25470 luke 628
    /* jump to a browser/try if one is on the stack */
629
    if (! ignoreRestartContexts)
630
	try_jump_to_restart();
14478 luke 631
 
25470 luke 632
    /* at this point, i.e. if we have not exited in
633
       try_jump_to_restart, we are heading for R_ToplevelContext */
634
 
27000 luke 635
    /* only run traceback if we are not going to bail out of a
636
       non-interactive session */
637
    if (R_Interactive || haveHandler) {
638
	/* write traceback if requested, unless we're already doing it
639
	   or there is an inconsistenty between inError and oldInError
640
	   (which should not happen) */
641
	if (traceback && inError < 2 && inError == oldInError) {
642
	    inError = 2;
643
	    PROTECT(s = R_GetTraceback(0));
644
	    setVar(install(".Traceback"), s, R_GlobalEnv);
645
	    UNPROTECT(1);
646
	    inError = oldInError;
647
	}
648
    }
649
 
25353 luke 650
    /* Run onexit/cend code for all contexts down to but not including
651
       the jump target.  This may cause recursive calls to
25472 luke 652
       jump_to_top_ex, but the possible number of such recursive
25353 luke 653
       calls is limited since each exit function is removed before it
654
       is executed.  In addition, all but the first should have
655
       inError > 0.  This is not a great design because we could run
656
       out of other resources that are on the stack (like C stack for
657
       example).  The right thing to do is arrange to execute exit
658
       code *after* the LONGJMP, but that requires a more extensive
659
       redesign of the non-local transfer of control mechanism.
660
       LT. */
661
    R_run_onexits(R_ToplevelContext);
14478 luke 662
 
25368 luke 663
    if ( !R_Interactive && !haveHandler ) {
6363 ripley 664
	REprintf("Execution halted\n");
6357 ripley 665
	R_CleanUp(SA_NOSAVE, 1, 0); /* quit, no save, no .Last, status=1 */
6363 ripley 666
    }
14478 luke 667
 
19318 luke 668
    R_GlobalContext = R_ToplevelContext;
669
    R_restore_globals(R_GlobalContext);
14479 luke 670
 
19318 luke 671
    LONGJMP(R_ToplevelContext->cjmpbuf, 0);
25353 luke 672
 
673
    /* not reached */
674
    endcontext(&cntxt);
25368 luke 675
    inError = oldInError;
2 r 676
}
677
 
25368 luke 678
void jump_to_toplevel()
679
{
680
    /* no traceback, no user error option; for now, warnings are
681
       printed here and console is reset -- eventually these should be
25370 luke 682
       done after arriving at the jump target.  Now ignores
683
       try/browser frames--it really is a jump to toplevel */
684
    jump_to_top_ex(FALSE, FALSE, TRUE, TRUE, TRUE);
25368 luke 685
}
686
 
25513 luke 687
static SEXP findCall(void)
688
{
689
    RCNTXT *cptr;
690
    for (cptr = R_GlobalContext->nextcontext;
691
	 cptr != NULL && cptr->callflag != CTXT_TOPLEVEL;
692
	 cptr = cptr->nextcontext)
693
	if (cptr->callflag & CTXT_FUNCTION)
694
	    return cptr->call;
695
    return R_NilValue;
696
}
697
 
10919 maechler 698
SEXP do_stop(SEXP call, SEXP op, SEXP args, SEXP rho)
2 r 699
{
10919 maechler 700
/* error(.) : really doesn't return anything; but all do_foo() must be SEXP */
8892 maechler 701
    SEXP c_call;
6199 rgentlem 702
 
25513 luke 703
    if(asLogical(CAR(args))) /* find context -> "Error in ..:" */
704
	c_call = findCall();
8892 maechler 705
    else
706
	c_call = R_NilValue;
6199 rgentlem 707
 
8892 maechler 708
    args = CDR(args);
709
 
710
    if (CAR(args) != R_NilValue) { /* message */
10172 luke 711
      SETCAR(args, coerceVector(CAR(args), STRSXP));
8004 maechler 712
      if(!isValidString(CAR(args)))
8892 maechler 713
	  errorcall(c_call, " [invalid string in stop(.)]");
10172 luke 714
      errorcall(c_call, "%s", CHAR(STRING_ELT(CAR(args), 0)));
6199 rgentlem 715
    }
1839 ihaka 716
    else
8892 maechler 717
      errorcall(c_call, "");
10919 maechler 718
    /* never called: */return c_call;
2 r 719
}
720
 
721
SEXP do_warning(SEXP call, SEXP op, SEXP args, SEXP rho)
722
{
18015 ripley 723
    SEXP c_call;
4179 rgentlem 724
 
25513 luke 725
    if(asLogical(CAR(args))) /* find context -> "... in: ..:" */
726
	c_call = findCall();
727
    else
18015 ripley 728
	c_call = R_NilValue;
729
 
730
    args = CDR(args);
1839 ihaka 731
    if (CAR(args) != R_NilValue) {
10172 luke 732
	SETCAR(args, coerceVector(CAR(args), STRSXP));
8004 maechler 733
	if(!isValidString(CAR(args)))
18015 ripley 734
	    warningcall(c_call, " [invalid string in warning(.)]");
8004 maechler 735
	else
18015 ripley 736
	    warningcall(c_call, "%s", CHAR(STRING_ELT(CAR(args), 0)));
1839 ihaka 737
    }
738
    else
18015 ripley 739
	warningcall(c_call, "");
25523 luke 740
 
741
    /* need to set R_Visible since it may have been changed by a callback */
742
    R_Visible = 0;
1839 ihaka 743
    return CAR(args);
2 r 744
}
745
 
2472 maechler 746
/* Error recovery for incorrect argument count error. */
13997 duncan 747
void WrongArgCount(const char *s)
2472 maechler 748
{
5731 ripley 749
    error("incorrect number of arguments to \"%s\"", s);
2472 maechler 750
}
751
 
752
 
13997 duncan 753
void UNIMPLEMENTED(const char *s)
2 r 754
{
5731 ripley 755
    error("Unimplemented feature in %s", s);
2 r 756
}
757
 
11046 maechler 758
/* ERROR_.. codes in Errormsg.h */
2 r 759
static struct {
13997 duncan 760
    const R_WARNING code;
761
    const char* const format;
2 r 762
}
13997 duncan 763
const ErrorDB[] = {
11046 maechler 764
    { ERROR_NUMARGS,		"invalid number of arguments"		},
765
    { ERROR_ARGTYPE,		"invalid argument type"			},
2 r 766
 
11046 maechler 767
    { ERROR_TSVEC_MISMATCH,	"time-series/vector length mismatch"	},
768
    { ERROR_INCOMPAT_ARGS,	"incompatible arguments"		},
2 r 769
 
11046 maechler 770
    { ERROR_UNIMPLEMENTED,	"unimplemented feature in %s"		},
771
    { ERROR_UNKNOWN,		"unknown error (report this!)"		}
2 r 772
};
773
 
11046 maechler 774
static struct {
775
    R_WARNING code;
776
    char* format;
777
}
778
WarningDB[] = {
779
    { WARNING_coerce_NA,	"NAs introduced by coercion"		},
780
    { WARNING_coerce_INACC,	"inaccurate integer conversion in coercion" },
781
    { WARNING_coerce_IMAG,	"imaginary parts discarded in coercion" },
782
 
783
    { WARNING_UNKNOWN,		"unknown warning (report this!)"	},
784
};
785
 
786
 
787
void ErrorMessage(SEXP call, int which_error, ...)
2 r 788
{
1839 ihaka 789
    int i;
14494 hornik 790
    char buf[BUFSIZE];
1839 ihaka 791
    va_list(ap);
14442 luke 792
 
1839 ihaka 793
    i = 0;
11046 maechler 794
    while(ErrorDB[i].code != ERROR_UNKNOWN) {
795
	if (ErrorDB[i].code == which_error)
1839 ihaka 796
	    break;
797
	i++;
798
    }
14442 luke 799
 
1839 ihaka 800
    va_start(ap, which_error);
14442 luke 801
    Rvsnprintf(buf, BUFSIZE, ErrorDB[i].format, ap);
1839 ihaka 802
    va_end(ap);
14442 luke 803
    errorcall(call, "%s", buf);
2 r 804
}
805
 
11046 maechler 806
void WarningMessage(SEXP call, R_WARNING which_warn, ...)
2 r 807
{
1839 ihaka 808
    int i;
14494 hornik 809
    char buf[BUFSIZE];
1839 ihaka 810
    va_list(ap);
14442 luke 811
 
1839 ihaka 812
    i = 0;
11046 maechler 813
    while(WarningDB[i].code != WARNING_UNKNOWN) {
814
	if (WarningDB[i].code == which_warn)
1839 ihaka 815
	    break;
816
	i++;
817
    }
14442 luke 818
 
1839 ihaka 819
    va_start(ap, which_warn);
14442 luke 820
    Rvsnprintf(buf, BUFSIZE, WarningDB[i].format, ap);
1839 ihaka 821
    va_end(ap);
14442 luke 822
    warningcall(call, "%s", buf);
2 r 823
}
14570 luke 824
 
825
 
826
/* Temporary hooks to allow experimenting with alternate error and
827
   warning mechanisms.  They are not in the header files for now, but
828
   the following snippet can serve as a header file: */
829
 
830
void R_ReturnOrRestart(SEXP val, SEXP env, Rboolean restart);
831
void R_PrintDeferredWarnings(void);
832
void R_SetErrmessage(char *s);
833
void R_SetErrorHook(void (*hook)(SEXP, char *));
834
void R_SetWarningHook(void (*hook)(SEXP, char *));
835
void R_JumpToToplevel(Rboolean restart);
836
 
837
 
838
void R_SetWarningHook(void (*hook)(SEXP, char *))
839
{
840
    R_WarningHook = hook;
841
}
842
 
843
void R_SetErrorHook(void (*hook)(SEXP, char *))
844
{
845
    R_ErrorHook = hook;
846
}
847
 
848
void R_ReturnOrRestart(SEXP val, SEXP env, Rboolean restart)
849
{
850
    int mask;
851
    RCNTXT *c;
852
 
14977 luke 853
    mask = CTXT_BROWSER | CTXT_FUNCTION;
14570 luke 854
 
855
    for (c = R_GlobalContext; c; c = c->nextcontext) {
856
	if (c->callflag & mask && c->cloenv == env)
857
	    findcontext(mask, env, val);
14631 luke 858
	else if (restart && IS_RESTART_BIT_SET(c->callflag))
14904 luke 859
	    findcontext(CTXT_RESTART, c->cloenv, R_RestartToken);
14570 luke 860
	else if (c->callflag == CTXT_TOPLEVEL)
861
	    error("No function to return from, jumping to top level");
862
    }
863
}
864
 
865
void R_JumpToToplevel(Rboolean restart)
866
{
867
    RCNTXT *c;
868
 
869
    /* Find the target for the jump */
870
    for (c = R_GlobalContext; c != NULL; c = c->nextcontext) {
14631 luke 871
	if (restart && IS_RESTART_BIT_SET(c->callflag))
14904 luke 872
	    findcontext(CTXT_RESTART, c->cloenv, R_RestartToken);
14570 luke 873
	else if (c->callflag == CTXT_TOPLEVEL)
874
	    break;
875
    }
876
    if (c != R_ToplevelContext)
877
	warning("top level inconsistency?");
878
 
879
    /* Run onexit/cend code for everything above the target. */
880
    R_run_onexits(c);
881
 
882
    R_ToplevelContext = R_GlobalContext = c;
19318 luke 883
    R_restore_globals(R_GlobalContext);
14570 luke 884
    LONGJMP(c->cjmpbuf, CTXT_TOPLEVEL);
885
}
886
 
887
void R_SetErrmessage(char *s)
888
{
889
    strncpy(errbuf, s, sizeof(errbuf));
890
    errbuf[sizeof(errbuf) - 1] = 0;
891
}
892
 
893
void R_PrintDeferredWarnings(void)
894
{
895
    if( R_ShowErrorMessages && R_CollectWarnings ) {
896
        REprintf("In addition: ");
897
        PrintWarnings();
898
    }
899
}    
900
 
901
SEXP R_GetTraceback(int skip)
902
{
903
    int nback = 0, ns;
904
    RCNTXT *c;
905
    SEXP s, t;
906
 
14723 luke 907
    for (c = R_GlobalContext, ns = skip;
908
	 c != NULL && c->callflag != CTXT_TOPLEVEL;
909
	 c = c->nextcontext)
910
	if (c->callflag & CTXT_FUNCTION ) {
14570 luke 911
	    if (ns > 0)
912
		ns--;
913
	    else
914
		nback++;
14629 ripley 915
	}
14570 luke 916
 
917
    PROTECT(s = allocList(nback));
918
    t = s;
14723 luke 919
    for (c = R_GlobalContext ;
920
	 c != NULL && c->callflag != CTXT_TOPLEVEL;
921
	 c = c->nextcontext)
14629 ripley 922
	if (c->callflag & CTXT_FUNCTION ) {
14570 luke 923
	    if (skip > 0)
924
		skip--;
925
	    else {
926
		SETCAR(t, deparse1(c->call, 0));
927
		t = CDR(t);
928
	    }
14629 ripley 929
	}
14570 luke 930
    UNPROTECT(1);
931
    return s;
932
}
933
 
25523 luke 934
#ifdef NEW_CONDITION_HANDLING
935
static SEXP mkHandlerEntry(SEXP class, SEXP parentenv, SEXP handler, SEXP rho,
936
			   SEXP result, int calling)
937
{
938
    SEXP entry = allocVector(VECSXP, 5);
939
    SET_VECTOR_ELT(entry, 0, class);
940
    SET_VECTOR_ELT(entry, 1, parentenv);
941
    SET_VECTOR_ELT(entry, 2, handler);
942
    SET_VECTOR_ELT(entry, 3, rho);
943
    SET_VECTOR_ELT(entry, 4, result);
944
    SETLEVELS(entry, calling);
945
    return entry;
946
}
947
 
948
/**** rename these??*/
949
#define IS_CALLING_ENTRY(e) LEVELS(e)
950
#define ENTRY_CLASS(e) VECTOR_ELT(e, 0)
951
#define ENTRY_CALLING_ENVIR(e) VECTOR_ELT(e, 1)
952
#define ENTRY_HANDLER(e) VECTOR_ELT(e, 2)
953
#define ENTRY_TARGET_ENVIR(e) VECTOR_ELT(e, 3)
954
#define ENTRY_RETURN_RESULT(e) VECTOR_ELT(e, 4)
955
 
956
#define RESULT_SIZE 3
957
 
958
SEXP do_addCondHands(SEXP call, SEXP op, SEXP args, SEXP rho)
959
{
960
    SEXP classes, handlers, parentenv, target, oldstack, newstack, result;
961
    int calling, i, n;
962
    PROTECT_INDEX osi;
963
 
964
    checkArity(op, args);
965
 
966
    classes = CAR(args); args = CDR(args);
967
    handlers = CAR(args); args = CDR(args);
968
    parentenv = CAR(args); args = CDR(args);
969
    target = CAR(args); args = CDR(args);
970
    calling = asLogical(CAR(args));
971
 
972
    if (classes == R_NilValue || handlers == R_NilValue)
973
	return R_HandlerStack;
974
 
975
    if (TYPEOF(classes) != STRSXP || TYPEOF(handlers) != VECSXP ||
976
	LENGTH(classes) != LENGTH(handlers))
977
	error("bad handler data");
978
 
979
    n = LENGTH(handlers);
980
    oldstack = R_HandlerStack;
981
 
982
    PROTECT(result = allocVector(VECSXP, RESULT_SIZE));
983
    PROTECT_WITH_INDEX(newstack = oldstack, &osi);
984
 
985
    for (i = n - 1; i >= 0; i--) {
986
	SEXP class = STRING_ELT(classes, i);
987
	SEXP handler = VECTOR_ELT(handlers, i);
988
	SEXP entry = mkHandlerEntry(class, parentenv, handler, target, result,
989
				    calling);
990
	REPROTECT(newstack = CONS(entry, newstack), osi);
991
    }
992
 
993
    R_HandlerStack = newstack;
994
    UNPROTECT(2);
995
 
996
    return oldstack;
997
}
998
 
999
SEXP do_resetCondHands(SEXP call, SEXP op, SEXP args, SEXP rho)
1000
{
1001
    checkArity(op, args);
1002
    R_HandlerStack = CAR(args);
1003
    return R_NilValue;
1004
}
1005
 
25526 luke 1006
static SEXP findSimpleErrorHandler()
25523 luke 1007
{
1008
    SEXP list;
1009
    for (list = R_HandlerStack; list != R_NilValue; list = CDR(list)) {
1010
	SEXP entry = CAR(list);
25526 luke 1011
	if (! strcmp(CHAR(ENTRY_CLASS(entry)), "simpleError") ||
1012
	    ! strcmp(CHAR(ENTRY_CLASS(entry)), "error") ||
25523 luke 1013
	    ! strcmp(CHAR(ENTRY_CLASS(entry)), "condition"))
1014
	    return list;
1015
    }
1016
    return R_NilValue;
1017
}
1018
 
1019
static void vsignalWarning(SEXP call, const char *format, va_list ap)
1020
{
1021
    char buf[BUFSIZE];
1022
    SEXP hooksym, quotesym, hcall, qcall;
1023
 
1024
    hooksym = install(".signalSimpleWarning");
1025
    quotesym = install("quote");
1026
    if (SYMVALUE(hooksym) != R_UnboundValue &&
1027
	SYMVALUE(quotesym) != R_UnboundValue) {
1028
	PROTECT(qcall = LCONS(quotesym, LCONS(call, R_NilValue)));
1029
	PROTECT(hcall = LCONS(qcall, R_NilValue));
1030
	Rvsnprintf(buf, BUFSIZE - 1, format, ap);
1031
	hcall = LCONS(ScalarString(mkChar(buf)), hcall);
1032
	PROTECT(hcall = LCONS(hooksym, hcall));
1033
	eval(hcall, R_GlobalEnv);
1034
	UNPROTECT(3);
1035
    }
1036
    else vwarningcall_dflt(call, format, ap);
1037
}
1038
 
1039
static void gotoExitingHandler(SEXP cond, SEXP call, SEXP entry)
1040
{
1041
    SEXP rho = ENTRY_TARGET_ENVIR(entry);
1042
    SEXP result = ENTRY_RETURN_RESULT(entry);
1043
    SET_VECTOR_ELT(result, 0, cond);
1044
    SET_VECTOR_ELT(result, 1, call);
1045
    SET_VECTOR_ELT(result, 2, ENTRY_HANDLER(entry));
1046
    findcontext(CTXT_FUNCTION, rho, result);
1047
}
1048
 
25526 luke 1049
static void vsignalError(SEXP call, const char *format, va_list ap)
25523 luke 1050
{
1051
    SEXP list, oldstack;
1052
 
26646 luke 1053
    oldstack = R_HandlerStack;
25526 luke 1054
    while ((list = findSimpleErrorHandler()) != R_NilValue) {
25523 luke 1055
	char *buf = errbuf;
1056
	SEXP entry = CAR(list);
1057
	R_HandlerStack = CDR(list);
1058
	Rvsnprintf(buf, BUFSIZE - 1, format, ap);
1059
	buf[BUFSIZE - 1] = 0;
1060
	if (IS_CALLING_ENTRY(entry)) {
26646 luke 1061
	    if (ENTRY_HANDLER(entry) == R_RestartToken)
25523 luke 1062
		return; /* go to default error handling; do not reset stack */
1063
	    else {
1064
		SEXP hooksym, quotesym, hcall, qcall;
26646 luke 1065
		/* protect oldstack here, not outside loop, so handler
1066
		   stack gets unwound in case error is protect stack
1067
		   overflow */
1068
		PROTECT(oldstack);
25526 luke 1069
		hooksym = install(".handleSimpleError");
25523 luke 1070
		quotesym = install("quote");
1071
		PROTECT(qcall = LCONS(quotesym, LCONS(call, R_NilValue)));
1072
		PROTECT(hcall = LCONS(qcall, R_NilValue));
1073
		hcall = LCONS(ScalarString(mkChar(buf)), hcall);
1074
		hcall = LCONS(ENTRY_HANDLER(entry), hcall);
1075
		PROTECT(hcall = LCONS(hooksym, hcall));
1076
		eval(hcall, R_GlobalEnv);
26646 luke 1077
		UNPROTECT(4);
25523 luke 1078
	    }
1079
	}
1080
	else gotoExitingHandler(R_NilValue, call, entry);
1081
    }
1082
    R_HandlerStack = oldstack;
1083
}
1084
 
1085
static SEXP findConditionHandler(SEXP cond)
1086
{
1087
    int i;
1088
    SEXP list;
1089
    SEXP classes = getAttrib(cond, R_ClassSymbol);
1090
 
1091
    if (TYPEOF(classes) != STRSXP)
1092
	return R_NilValue;
1093
 
25526 luke 1094
    /**** need some changes here to allow conditions to be S4 classes */
25523 luke 1095
    for (list = R_HandlerStack; list != R_NilValue; list = CDR(list)) {
1096
	SEXP entry = CAR(list);
1097
	for (i = 0; i < LENGTH(classes); i++)
1098
	    if (! strcmp(CHAR(ENTRY_CLASS(entry)),
1099
			 CHAR(STRING_ELT(classes, i))))
1100
		return list;
1101
    }
1102
    return R_NilValue;
1103
}
1104
 
1105
SEXP do_signalCondition(SEXP call, SEXP op, SEXP args, SEXP rho)
1106
{
26352 luke 1107
    SEXP list, cond, msg, ecall, oldstack;
25523 luke 1108
 
1109
    checkArity(op, args);
1110
 
1111
    cond = CAR(args);
1112
    msg = CADR(args);
1113
    ecall = CADDR(args);
1114
 
26352 luke 1115
    PROTECT(oldstack = R_HandlerStack);
25523 luke 1116
    while ((list = findConditionHandler(cond)) != R_NilValue) {
1117
	SEXP entry = CAR(list);
1118
	R_HandlerStack = CDR(list);
1119
	if (IS_CALLING_ENTRY(entry)) {
1120
	    SEXP h = ENTRY_HANDLER(entry);
1121
	    if (h == R_RestartToken) {
1122
		char *msgstr = NULL;
1123
		if (TYPEOF(msg) == STRSXP && LENGTH(msg) > 0)
1124
		    msgstr = CHAR(STRING_ELT(msg, 0));
1125
		else error("error message not a strring");
1126
		errorcall_dflt(ecall, "%s", msgstr);
1127
	    }
1128
	    else {
1129
		SEXP hcall = LCONS(h, LCONS(cond, R_NilValue));
1130
		PROTECT(hcall);
1131
		eval(hcall, R_GlobalEnv);
1132
		UNPROTECT(1);
1133
	    }
1134
	}
26353 luke 1135
	else gotoExitingHandler(cond, ecall, entry);
25523 luke 1136
    }
26352 luke 1137
    R_HandlerStack = oldstack;
1138
    UNPROTECT(1);
25523 luke 1139
    return R_NilValue;
1140
}
1141
 
26354 luke 1142
static SEXP findInterruptHandler()
1143
{
1144
    SEXP list;
1145
    for (list = R_HandlerStack; list != R_NilValue; list = CDR(list)) {
1146
	SEXP entry = CAR(list);
1147
	if (! strcmp(CHAR(ENTRY_CLASS(entry)), "interrupt") ||
1148
	    ! strcmp(CHAR(ENTRY_CLASS(entry)), "condition"))
1149
	    return list;
1150
    }
1151
    return R_NilValue;
1152
}
1153
 
1154
static SEXP getInterruptCondition()
1155
{
1156
    /**** FIXME: should probably pre-allocate this */
1157
    SEXP cond, class;
1158
    PROTECT(cond = allocVector(VECSXP, 0));
1159
    PROTECT(class = allocVector(STRSXP, 2));
1160
    SET_STRING_ELT(class, 0, mkChar("interrupt"));
1161
    SET_STRING_ELT(class, 1, mkChar("condition"));
1162
    R_set_class(cond, class, R_NilValue);
1163
    UNPROTECT(2);
1164
    return cond;
1165
}
1166
 
1167
static void signalInterrupt(void)
1168
{
1169
    SEXP list, cond, oldstack;
1170
 
1171
    PROTECT(oldstack = R_HandlerStack);
1172
    while ((list = findInterruptHandler()) != R_NilValue) {
1173
	SEXP entry = CAR(list);
1174
	R_HandlerStack = CDR(list);
1175
	PROTECT(cond = getInterruptCondition());
1176
	if (IS_CALLING_ENTRY(entry)) {
1177
	    SEXP h = ENTRY_HANDLER(entry);
1178
	    SEXP hcall = LCONS(h, LCONS(cond, R_NilValue));
1179
	    PROTECT(hcall);
1180
	    eval(hcall, R_GlobalEnv);
1181
	    UNPROTECT(1);
1182
	}
1183
	else gotoExitingHandler(cond, R_NilValue, entry);
1184
	UNPROTECT(1);
1185
    }
1186
    R_HandlerStack = oldstack;
1187
    UNPROTECT(1);
1188
}
1189
 
25523 luke 1190
void R_InsertRestartHandlers(RCNTXT *cptr, Rboolean browser)
1191
{
1192
    SEXP class, rho, entry, name;
1193
 
1194
    if ((cptr->handlerstack != R_HandlerStack ||
1195
	 cptr->handlerstack != R_HandlerStack)) {
1196
	if (IS_RESTART_BIT_SET(cptr->callflag))
1197
	    return;
1198
	else
1199
	    error("handler or restart stack mismatch in old restart");
1200
    }
1201
 
1202
    /**** need more here to keep recursive errors in browser? */
1203
    rho = cptr->cloenv;
25526 luke 1204
    PROTECT(class = mkChar("error"));
25523 luke 1205
    entry = mkHandlerEntry(class, rho, R_RestartToken, rho, R_NilValue, TRUE);
1206
    R_HandlerStack = CONS(entry, R_HandlerStack);
1207
    UNPROTECT(1);
1208
    PROTECT(name = ScalarString(mkChar(browser ? "browser" : "tryRestart")));
1209
    entry = allocVector(VECSXP, 2);
1210
    SET_VECTOR_ELT(entry, 0, name);
1211
    SET_VECTOR_ELT(entry, 1, R_MakeExternalPtr(cptr, R_NilValue, R_NilValue));
1212
    setAttrib(entry, R_ClassSymbol, ScalarString(mkChar("restart")));
1213
    R_RestartStack = CONS(entry, R_RestartStack);
1214
    UNPROTECT(1);
1215
}
1216
 
1217
SEXP do_dfltWarn(SEXP call, SEXP op, SEXP args, SEXP rho)
1218
{
1219
    char *msg;
1220
    SEXP ecall;
1221
 
1222
    checkArity(op, args);
1223
 
1224
    if (TYPEOF(CAR(args)) != STRSXP || LENGTH(CAR(args)) != 1)
1225
	error("bad error message");
1226
    msg = CHAR(STRING_ELT(CAR(args), 0));
1227
    ecall = CADR(args);
1228
 
1229
    warningcall_dflt(ecall, "%s", msg);
1230
    return R_NilValue;
1231
}
1232
 
1233
SEXP do_dfltStop(SEXP call, SEXP op, SEXP args, SEXP rho)
1234
{
1235
    char *msg;
1236
    SEXP ecall;
1237
 
1238
    checkArity(op, args);
1239
 
1240
    if (TYPEOF(CAR(args)) != STRSXP || LENGTH(CAR(args)) != 1)
1241
	error("bad error message");
1242
    msg = CHAR(STRING_ELT(CAR(args), 0));
1243
    ecall = CADR(args);
1244
 
1245
    errorcall_dflt(ecall, "%s", msg);
1246
    return R_NilValue; /* not reached */
1247
}
1248
 
1249
 
1250
/*
1251
 * Restart Handling
1252
 */
1253
 
1254
SEXP do_getRestart(SEXP call, SEXP op, SEXP args, SEXP rho)
1255
{
1256
    int i;
1257
    SEXP list;
1258
    checkArity(op, args);
1259
    i = asInteger(CAR(args));
1260
    for (list = R_RestartStack;
1261
	 list != R_NilValue && i > 1;
1262
	 list = CDR(list), i--);
1263
    if (list != R_NilValue)
1264
	return CAR(list);
1265
    else if (i == 1) {
1266
	/**** need to pre-allocate */
1267
	SEXP name, entry;
1268
	PROTECT(name = ScalarString(mkChar("abort")));
1269
	entry = allocVector(VECSXP, 2);
1270
	SET_VECTOR_ELT(entry, 0, name);
1271
	SET_VECTOR_ELT(entry, 1, R_NilValue);
1272
	setAttrib(entry, R_ClassSymbol, ScalarString(mkChar("restart")));
1273
	UNPROTECT(1);
1274
	return entry;
1275
    }
1276
    else return R_NilValue;
1277
}
1278
 
1279
/* very minimal error checking --just enough to avoid a segfault */
1280
#define CHECK_RESTART(r) do { \
1281
    SEXP __r__ = (r); \
1282
    if (TYPEOF(__r__) != VECSXP || LENGTH(__r__) < 2) \
1283
	error("bad restart"); \
1284
} while (0)
1285
 
1286
SEXP do_addRestart(SEXP call, SEXP op, SEXP args, SEXP rho)
1287
{
1288
    checkArity(op, args);
1289
    CHECK_RESTART(CAR(args));
1290
    R_RestartStack = CONS(CAR(args), R_RestartStack);
1291
    return R_NilValue;
1292
}
1293
 
1294
#define RESTART_EXIT(r) VECTOR_ELT(r, 1)
1295
 
1296
static void invokeRestart(SEXP r, SEXP arglist)
1297
{
1298
    SEXP exit = RESTART_EXIT(r);
1299
 
1300
    if (exit == R_NilValue) {
1301
	R_RestartStack = R_NilValue;
1302
	jump_to_toplevel();
1303
    }
1304
    else {
1305
	for (; R_RestartStack != R_NilValue;
1306
	     R_RestartStack = CDR(R_RestartStack))
1307
	    if (exit == RESTART_EXIT(CAR(R_RestartStack))) {
1308
		R_RestartStack = CDR(R_RestartStack);
1309
		if (TYPEOF(exit) == EXTPTRSXP) {
1310
		    RCNTXT *c = R_ExternalPtrAddr(exit);
1311
		    R_JumpToContext(c, CTXT_RESTART, R_RestartToken);
1312
		}
1313
		else findcontext(CTXT_FUNCTION, exit, arglist);
1314
	    }
1315
	error("restart not on stack");
1316
    }
1317
}
1318
 
1319
SEXP do_invokeRestart(SEXP call, SEXP op, SEXP args, SEXP rho)
1320
{
1321
    checkArity(op, args);
1322
    CHECK_RESTART(CAR(args));
1323
    invokeRestart(CAR(args), CADR(args));
1324
    return R_NilValue; /* not reached */
1325
}
1326
#endif
1327
 
25517 luke 1328
SEXP do_addTryHandlers(SEXP call, SEXP op, SEXP args, SEXP rho)
1329
{
1330
    checkArity(op, args);
1331
    if (R_GlobalContext == R_ToplevelContext ||
1332
	! R_GlobalContext->callflag & CTXT_FUNCTION)
1333
	errorcall(call, "not in a try context");
1334
    SET_RESTART_BIT_ON(R_GlobalContext->callflag);
25523 luke 1335
#ifdef NEW_CONDITION_HANDLING
1336
    R_InsertRestartHandlers(R_GlobalContext, FALSE);
1337
#endif
25517 luke 1338
    return R_NilValue;
1339
}