The R Project SVN R

Rev

Rev 29864 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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