The R Project SVN R

Rev

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

Rev 41966 Rev 42208
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--2007  The R Development Core Team.
4
 *  Copyright (C) 1997--2007  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., 51 Franklin Street Fifth Floor, Boston, MA 02110-1301  USA
18
 *  Foundation, Inc., 51 Franklin Street Fifth Floor, Boston, MA 02110-1301  USA
19
 */
19
 */
20
 
20
 
21
/* <UTF8> char here is either ASCII or handled as a whole */
21
/* <UTF8> char here is either ASCII or handled as a whole */
22
 
22
 
23
#ifdef HAVE_CONFIG_H
23
#ifdef HAVE_CONFIG_H
24
#include <config.h>
24
#include <config.h>
25
#endif
25
#endif
26
 
26
 
27
/* Now in Defn.h
27
/* Now in Defn.h
28
#ifdef HAVE_AQUA
28
#ifdef HAVE_AQUA
29
extern void R_ProcessEvents(void);
29
extern void R_ProcessEvents(void);
30
#endif
30
#endif
31
*/
31
*/
32
 
32
 
33
#include <Defn.h>
33
#include <Defn.h>
34
/* -> Errormsg.h */
34
/* -> Errormsg.h */
35
#include <Startup.h> /* rather cleanup ..*/
35
#include <Startup.h> /* rather cleanup ..*/
36
#include <Rconnections.h>
36
#include <Rconnections.h>
37
#include <Rinterface.h>
37
#include <Rinterface.h>
38
#include <R_ext/GraphicsDevice.h>
38
#include <R_ext/GraphicsDevice.h>
39
#include <R_ext/GraphicsEngine.h> /* for GEonExit */
39
#include <R_ext/GraphicsEngine.h> /* for GEonExit */
40
#include <Rmath.h> /* for imax2 */
40
#include <Rmath.h> /* for imax2 */
41
#if  !( defined(HAVE_AQUA) || defined(Win32) )
41
#if  !( defined(HAVE_AQUA) || defined(Win32) )
42
#include <R_ext/eventloop.h> /* for R_PolledEvents */
42
#include <R_ext/eventloop.h> /* for R_PolledEvents */
43
#endif
43
#endif
44
 
44
 
45
#ifndef min
45
#ifndef min
46
#define min(a, b) (a<b?a:b)
46
#define min(a, b) (a<b?a:b)
47
#endif
47
#endif
48
 
48
 
49
/* Total line length, in chars, before splitting in warnings/errors */
49
/* Total line length, in chars, before splitting in warnings/errors */
50
#define LONGWARN 75
50
#define LONGWARN 75
51
 
51
 
52
/*
52
/*
53
Different values of inError are used to indicate different places
53
Different values of inError are used to indicate different places
54
in the error handling.
54
in the error handling.
55
*/
55
*/
56
static int inError = 0;
56
static int inError = 0;
57
static int inWarning = 0;
57
static int inWarning = 0;
58
static int inPrintWarnings = 0;
58
static int inPrintWarnings = 0;
59
static int immediateWarning = 0;
59
static int immediateWarning = 0;
60
 
60
 
61
static void try_jump_to_restart(void);
61
static void try_jump_to_restart(void);
62
static void jump_to_top_ex(Rboolean, Rboolean, Rboolean, Rboolean, Rboolean);
62
static void jump_to_top_ex(Rboolean, Rboolean, Rboolean, Rboolean, Rboolean);
63
static void signalInterrupt(void);
63
static void signalInterrupt(void);
64
static char * R_ConciseTraceback(SEXP call, int skip);
64
static char * R_ConciseTraceback(SEXP call, int skip);
65
 
65
 
66
/* Interface / Calling Hierarchy :
66
/* Interface / Calling Hierarchy :
67
 
67
 
68
  R__stop()   -> do_error ->   errorcall --> jump_to_top_ex
68
  R__stop()   -> do_error ->   errorcall --> jump_to_top_ex
69
			 /
69
			 /
70
		    error
70
		    error
71
 
71
 
72
  R__warning()-> do_warning   -> warningcall -> if(warn >= 2) errorcall
72
  R__warning()-> do_warning   -> warningcall -> if(warn >= 2) errorcall
73
			     /
73
			     /
74
		    warning /
74
		    warning /
75
 
75
 
76
  ErrorMessage()-> errorcall   (but with message from ErrorDB[])
76
  ErrorMessage()-> errorcall   (but with message from ErrorDB[])
77
 
77
 
78
  WarningMessage()-> warningcall (but with message from WarningDB[]).
78
  WarningMessage()-> warningcall (but with message from WarningDB[]).
79
*/
79
*/
80
 
80
 
81
static void reset_stack_limit(void *data)
81
static void reset_stack_limit(void *data)
82
{
82
{
83
    unsigned int *limit = (unsigned int *) data;
83
    unsigned int *limit = (unsigned int *) data;
84
    R_CStackLimit = *limit;
84
    R_CStackLimit = *limit;
85
}
85
}
86
 
86
 
87
void R_CheckStack(void)
87
void R_CheckStack(void)
88
{
88
{
89
    int dummy;
89
    int dummy;
90
    long usage = R_CStackDir * (R_CStackStart - (unsigned long)&dummy);
90
    long usage = R_CStackDir * (R_CStackStart - (unsigned long)&dummy);
91
 
91
 
92
    /* printf("usage %ld\n", usage); */
92
    /* printf("usage %ld\n", usage); */
93
    if(R_CStackLimit != -1 && usage > 0.95 * R_CStackLimit) {
93
    if(R_CStackLimit != -1 && usage > 0.95 * R_CStackLimit) {
94
	/* We do need some stack space to process error recovery,
94
	/* We do need some stack space to process error recovery,
95
	   so temporarily raise the limit.
95
	   so temporarily raise the limit.
96
	 */
96
	 */
97
	RCNTXT cntxt;
97
	RCNTXT cntxt;
98
	unsigned int stacklimit = R_CStackLimit;
98
	unsigned int stacklimit = R_CStackLimit;
99
	R_CStackLimit += 0.05*R_CStackLimit;
99
	R_CStackLimit += 0.05*R_CStackLimit;
100
	begincontext(&cntxt, CTXT_CCODE, R_NilValue, R_BaseEnv, R_BaseEnv,
100
	begincontext(&cntxt, CTXT_CCODE, R_NilValue, R_BaseEnv, R_BaseEnv,
101
		     R_NilValue, R_NilValue);
101
		     R_NilValue, R_NilValue);
102
	cntxt.cend = &reset_stack_limit;
102
	cntxt.cend = &reset_stack_limit;
103
	cntxt.cenddata = &stacklimit;
103
	cntxt.cenddata = &stacklimit;
104
	
104
	
105
        errorcall(R_NilValue, "C stack usage is too close to the limit");
105
        errorcall(R_NilValue, "C stack usage is too close to the limit");
106
	/* Do not translate this, to save stack space */
106
	/* Do not translate this, to save stack space */
107
    }
107
    }
108
}
108
}
109
 
109
 
110
void R_CheckUserInterrupt(void)
110
void R_CheckUserInterrupt(void)
111
{
111
{
112
    R_CheckStack();
112
    R_CheckStack();
113
    /* This is the point where GUI systems need to do enough event
113
    /* This is the point where GUI systems need to do enough event
114
       processing to determine whether there is a user interrupt event
114
       processing to determine whether there is a user interrupt event
115
       pending.  Need to be careful not to do too much event
115
       pending.  Need to be careful not to do too much event
116
       processing though: if event handlers written in R are allowed
116
       processing though: if event handlers written in R are allowed
117
       to run at this point then we end up with concurrent R
117
       to run at this point then we end up with concurrent R
118
       evaluations and that can cause problems until we have proper
118
       evaluations and that can cause problems until we have proper
119
       concurrency support. LT */
119
       concurrency support. LT */
120
#if  ( defined(HAVE_AQUA) || defined(Win32) )
120
#if  ( defined(HAVE_AQUA) || defined(Win32) )
121
    R_ProcessEvents();
121
    R_ProcessEvents();
122
#else
122
#else
123
    R_PolledEvents();
123
    R_PolledEvents();
124
    if (R_interrupts_pending)
124
    if (R_interrupts_pending)
125
	onintr();
125
	onintr();
126
#endif /* Win32 */
126
#endif /* Win32 */
127
}
127
}
128
 
128
 
129
void onintr()
129
void onintr()
130
{
130
{
131
    if (R_interrupts_suspended) {
131
    if (R_interrupts_suspended) {
132
	R_interrupts_pending = 1;
132
	R_interrupts_pending = 1;
133
	return;
133
	return;
134
    }
134
    }
135
    else R_interrupts_pending = 0;
135
    else R_interrupts_pending = 0;
136
    signalInterrupt();
136
    signalInterrupt();
137
 
137
 
138
    REprintf("\n");
138
    REprintf("\n");
139
    /* Attempt to run user error option, save a traceback, show
139
    /* Attempt to run user error option, save a traceback, show
140
       warnings, and reset console; also stop at restart (try/browser)
140
       warnings, and reset console; also stop at restart (try/browser)
141
       frames.  Not clear this is what we really want, but this
141
       frames.  Not clear this is what we really want, but this
142
       preserves current behavior */
142
       preserves current behavior */
143
    jump_to_top_ex(TRUE, TRUE, TRUE, TRUE, FALSE);
143
    jump_to_top_ex(TRUE, TRUE, TRUE, TRUE, FALSE);
144
}
144
}
145
 
145
 
146
/* SIGUSR1: save and quit
146
/* SIGUSR1: save and quit
147
   SIGUSR2: save and quit, don't run .Last or on.exit().
147
   SIGUSR2: save and quit, don't run .Last or on.exit().
148
 
148
 
149
   These do far more processing than is allowed in a signal handler ....
149
   These do far more processing than is allowed in a signal handler ....
150
*/
150
*/
151
 
151
 
152
RETSIGTYPE attribute_hidden onsigusr1(int dummy)
152
RETSIGTYPE attribute_hidden onsigusr1(int dummy)
153
{
153
{
154
    if (R_interrupts_suspended) {
154
    if (R_interrupts_suspended) {
155
	/**** ought to save signal and handle after suspend */
155
	/**** ought to save signal and handle after suspend */
156
	REprintf(_("interrupts suspended; signal ignored"));
156
	REprintf(_("interrupts suspended; signal ignored"));
157
	signal(SIGUSR1, onsigusr1);
157
	signal(SIGUSR1, onsigusr1);
158
	return;
158
	return;
159
    }
159
    }
160
 
160
 
161
    inError = 1;
161
    inError = 1;
162
 
162
 
163
    if(R_CollectWarnings) PrintWarnings();
163
    if(R_CollectWarnings) PrintWarnings();
164
 
164
 
165
    R_ResetConsole();
165
    R_ResetConsole();
166
    R_FlushConsole();
166
    R_FlushConsole();
167
    R_ClearerrConsole();
167
    R_ClearerrConsole();
168
    R_ParseError = 0;    
168
    R_ParseError = 0;    
169
    R_ParseErrorFile = NULL;
169
    R_ParseErrorFile = NULL;
170
    R_ParseErrorMsg[0] = '\0';
170
    R_ParseErrorMsg[0] = '\0';
171
 
171
 
172
    /* Bail out if there is a browser/try on the stack--do we really
172
    /* Bail out if there is a browser/try on the stack--do we really
173
       want this?  No, as from R 2.4.0
173
       want this?  No, as from R 2.4.0
174
    try_jump_to_restart(); */
174
    try_jump_to_restart(); */
175
 
175
 
176
    /* Run all onexit/cend code on the stack (without stopping at
176
    /* Run all onexit/cend code on the stack (without stopping at
177
       intervening CTXT_TOPLEVEL's.  Since intervening CTXT_TOPLEVEL's
177
       intervening CTXT_TOPLEVEL's.  Since intervening CTXT_TOPLEVEL's
178
       get used by what are conceptually concurrent computations, this
178
       get used by what are conceptually concurrent computations, this
179
       is a bit like telling all active threads to terminate and clean
179
       is a bit like telling all active threads to terminate and clean
180
       up on the way out. */
180
       up on the way out. */
181
    R_run_onexits(NULL);
181
    R_run_onexits(NULL);
182
 
182
 
183
    R_CleanUp(SA_SAVE, 2, 1); /* quit, save,  .Last, status=2 */
183
    R_CleanUp(SA_SAVE, 2, 1); /* quit, save,  .Last, status=2 */
184
}
184
}
185
 
185
 
186
 
186
 
187
RETSIGTYPE attribute_hidden onsigusr2(int dummy)
187
RETSIGTYPE attribute_hidden onsigusr2(int dummy)
188
{
188
{
189
    inError = 1;
189
    inError = 1;
190
 
190
 
191
    if (R_interrupts_suspended) {
191
    if (R_interrupts_suspended) {
192
	/**** ought to save signal and handle after suspend */
192
	/**** ought to save signal and handle after suspend */
193
	REprintf(_("interrupts suspended; signal ignored"));
193
	REprintf(_("interrupts suspended; signal ignored"));
194
	signal(SIGUSR2, onsigusr2);
194
	signal(SIGUSR2, onsigusr2);
195
	return;
195
	return;
196
    }
196
    }
197
 
197
 
198
    if(R_CollectWarnings) PrintWarnings();
198
    if(R_CollectWarnings) PrintWarnings();
199
 
199
 
200
    R_ResetConsole();
200
    R_ResetConsole();
201
    R_FlushConsole();
201
    R_FlushConsole();
202
    R_ClearerrConsole();
202
    R_ClearerrConsole();
203
    R_ParseError = 0;
203
    R_ParseError = 0;
204
    R_ParseErrorFile = NULL;
204
    R_ParseErrorFile = NULL;
205
    R_ParseErrorMsg[0] = '\0';    
205
    R_ParseErrorMsg[0] = '\0';    
206
    R_CleanUp(SA_SAVE, 0, 0);
206
    R_CleanUp(SA_SAVE, 0, 0);
207
}
207
}
208
 
208
 
209
 
209
 
210
static void setupwarnings(void)
210
static void setupwarnings(void)
211
{
211
{
212
    R_Warnings = allocVector(VECSXP, 50);
212
    R_Warnings = allocVector(VECSXP, 50);
213
    setAttrib(R_Warnings, R_NamesSymbol, allocVector(STRSXP, 50));
213
    setAttrib(R_Warnings, R_NamesSymbol, allocVector(STRSXP, 50));
214
}
214
}
215
 
215
 
216
/* Rvsnprintf: like vsnprintf, but guaranteed to null-terminate. */
216
/* Rvsnprintf: like vsnprintf, but guaranteed to null-terminate. */
217
static int Rvsnprintf(char *buf, size_t size, const char  *format, va_list ap)
217
static int Rvsnprintf(char *buf, size_t size, const char  *format, va_list ap)
218
{
218
{
219
    int val;
219
    int val;
220
    val = vsnprintf(buf, size, format, ap);
220
    val = vsnprintf(buf, size, format, ap);
221
    buf[size-1] = '\0';
221
    buf[size-1] = '\0';
222
    return val;
222
    return val;
223
}
223
}
224
 
224
 
225
#define BUFSIZE 8192
225
#define BUFSIZE 8192
226
void warning(const char *format, ...)
226
void warning(const char *format, ...)
227
{
227
{
228
    char buf[BUFSIZE], *p;
228
    char buf[BUFSIZE], *p;
229
    RCNTXT *c = R_GlobalContext;
229
    RCNTXT *c = R_GlobalContext;
230
 
230
 
231
    va_list(ap);
231
    va_list(ap);
232
    va_start(ap, format);
232
    va_start(ap, format);
233
    Rvsnprintf(buf, min(BUFSIZE, R_WarnLength+1), format, ap);
233
    Rvsnprintf(buf, min(BUFSIZE, R_WarnLength+1), format, ap);
234
    va_end(ap);
234
    va_end(ap);
235
    p = buf + strlen(buf) - 1;
235
    p = buf + strlen(buf) - 1;
236
    if(strlen(buf) > 0 && *p == '\n') *p = '\0';
236
    if(strlen(buf) > 0 && *p == '\n') *p = '\0';
237
    if(R_WarnLength < BUFSIZE - 20 && strlen(buf) == R_WarnLength)
237
    if(R_WarnLength < BUFSIZE - 20 && strlen(buf) == R_WarnLength)
238
	strcat(buf, " [... truncated]");
238
	strcat(buf, " [... truncated]");
239
    if (c && (c->callflag & CTXT_BUILTIN)) c = c->nextcontext;
239
    if (c && (c->callflag & CTXT_BUILTIN)) c = c->nextcontext;
240
    warningcall(c ? c->call : R_NilValue, "%s", buf);
240
    warningcall(c ? c->call : R_NilValue, "%s", buf);
241
}
241
}
242
 
242
 
243
/* temporary hook to allow experimenting with alternate warning mechanisms */
243
/* temporary hook to allow experimenting with alternate warning mechanisms */
244
static void (*R_WarningHook)(SEXP, char *) = NULL;
244
static void (*R_WarningHook)(SEXP, char *) = NULL;
245
 
245
 
246
/* declarations for internal condition handling */
246
/* declarations for internal condition handling */
247
 
247
 
248
static void vsignalError(SEXP call, const char *format, va_list ap);
248
static void vsignalError(SEXP call, const char *format, va_list ap);
249
static void vsignalWarning(SEXP call, const char *format, va_list ap);
249
static void vsignalWarning(SEXP call, const char *format, va_list ap);
250
static void invokeRestart(SEXP, SEXP);
250
static void invokeRestart(SEXP, SEXP);
251
 
251
 
252
static void reset_inWarning(void *data)
252
static void reset_inWarning(void *data)
253
{
253
{
254
    inWarning = 0;
254
    inWarning = 0;
255
}
255
}
256
 
256
 
257
#ifdef SUPPORT_MBCS
257
#ifdef SUPPORT_MBCS
258
#include <R_ext/rlocale.h>
258
#include <R_ext/rlocale.h>
259
 
259
 
260
static int wd(const char * buf)
260
static int wd(const char * buf)
261
{
261
{
262
    int nc = mbstowcs(NULL, buf, 0), nw;
262
    int nc = mbstowcs(NULL, buf, 0), nw;
263
    if(nc > 0 && nc < 2000) {
263
    if(nc > 0 && nc < 2000) {
264
	wchar_t wc[2000];
264
	wchar_t wc[2000];
265
	mbstowcs(wc, buf, nc + 1);
265
	mbstowcs(wc, buf, nc + 1);
266
	nw = Ri18n_wcswidth(wc, 2147483647);
266
	nw = Ri18n_wcswidth(wc, 2147483647);
267
	return (nw < 1) ? nc : nw;
267
	return (nw < 1) ? nc : nw;
268
    }
268
    }
269
    return nc;
269
    return nc;
270
}
270
}
271
#endif
271
#endif
272
 
272
 
273
static void vwarningcall_dflt(SEXP call, const char *format, va_list ap)
273
static void vwarningcall_dflt(SEXP call, const char *format, va_list ap)
274
{
274
{
275
    int w;
275
    int w;
276
    SEXP names, s;
276
    SEXP names, s;
277
    const char *dcall;
277
    const char *dcall;
278
    char buf[BUFSIZE];
278
    char buf[BUFSIZE];
279
    RCNTXT *cptr;
279
    RCNTXT *cptr;
280
    RCNTXT cntxt;
280
    RCNTXT cntxt;
281
 
281
 
282
    if (inWarning)
282
    if (inWarning)
283
	return;
283
	return;
284
 
284
 
285
    s = GetOption(install("warning.expression"), R_BaseEnv);
285
    s = GetOption(install("warning.expression"), R_BaseEnv);
286
    if( s != R_NilValue ) {
286
    if( s != R_NilValue ) {
287
	if( !isLanguage(s) &&  ! isExpression(s) )
287
	if( !isLanguage(s) &&  ! isExpression(s) )
288
	    error(_("invalid option \"warning.expression\""));
288
	    error(_("invalid option \"warning.expression\""));
289
	cptr = R_GlobalContext;
289
	cptr = R_GlobalContext;
290
	while ( !(cptr->callflag & CTXT_FUNCTION) && cptr->callflag )
290
	while ( !(cptr->callflag & CTXT_FUNCTION) && cptr->callflag )
291
	    cptr = cptr->nextcontext;
291
	    cptr = cptr->nextcontext;
292
	eval(s, cptr->cloenv);
292
	eval(s, cptr->cloenv);
293
	return;
293
	return;
294
    }
294
    }
295
 
295
 
296
    w = asInteger(GetOption(install("warn"), R_BaseEnv));
296
    w = asInteger(GetOption(install("warn"), R_BaseEnv));
297
 
297
 
298
    if( w == NA_INTEGER ) /* set to a sensible value */
298
    if( w == NA_INTEGER ) /* set to a sensible value */
299
	w = 0;
299
	w = 0;
300
 
300
 
301
    if( w <= 0 && immediateWarning ) w = 1;
301
    if( w <= 0 && immediateWarning ) w = 1;
302
 
302
 
303
    if( w < 0 || inWarning || inError) /* ignore if w<0 or already in here*/
303
    if( w < 0 || inWarning || inError) /* ignore if w<0 or already in here*/
304
	return;
304
	return;
305
 
305
 
306
    /* set up a context which will restore inWarning if there is an exit */
306
    /* set up a context which will restore inWarning if there is an exit */
307
    begincontext(&cntxt, CTXT_CCODE, R_NilValue, R_BaseEnv, R_BaseEnv,
307
    begincontext(&cntxt, CTXT_CCODE, R_NilValue, R_BaseEnv, R_BaseEnv,
308
		 R_NilValue, R_NilValue);
308
		 R_NilValue, R_NilValue);
309
    cntxt.cend = &reset_inWarning;
309
    cntxt.cend = &reset_inWarning;
310
 
310
 
311
    inWarning = 1;
311
    inWarning = 1;
312
 
312
 
313
    if(w >= 2) { /* make it an error */
313
    if(w >= 2) { /* make it an error */
314
	Rvsnprintf(buf, min(BUFSIZE, R_WarnLength), format, ap);
314
	Rvsnprintf(buf, min(BUFSIZE, R_WarnLength), format, ap);
315
	if(R_WarnLength < BUFSIZE - 20 && strlen(buf) == R_WarnLength)
315
	if(R_WarnLength < BUFSIZE - 20 && strlen(buf) == R_WarnLength)
316
	    strcat(buf, " [... truncated]");
316
	    strcat(buf, " [... truncated]");
317
	inWarning = 0; /* PR#1570 */
317
	inWarning = 0; /* PR#1570 */
318
	errorcall(call, _("(converted from warning) %s"), buf);
318
	errorcall(call, _("(converted from warning) %s"), buf);
319
    }
319
    }
320
    else if(w == 1) {	/* print as they happen */
320
    else if(w == 1) {	/* print as they happen */
321
	char *tr;
321
	char *tr;
322
	if( call != R_NilValue ) {
322
	if( call != R_NilValue ) {
323
	    dcall = CHAR(STRING_ELT(deparse1(call, 0, DEFAULTDEPARSE), 0));
323
	    dcall = CHAR(STRING_ELT(deparse1(call, 0, DEFAULTDEPARSE), 0));
324
	} else dcall = "";
324
	} else dcall = "";
325
	Rvsnprintf(buf, min(BUFSIZE, R_WarnLength+1), format, ap);
325
	Rvsnprintf(buf, min(BUFSIZE, R_WarnLength+1), format, ap);
326
	if(R_WarnLength < BUFSIZE - 20 && strlen(buf) == R_WarnLength)
326
	if(R_WarnLength < BUFSIZE - 20 && strlen(buf) == R_WarnLength)
327
	    strcat(buf, " [... truncated]");
327
	    strcat(buf, " [... truncated]");
328
	if(dcall[0] == '\0')
328
	if(dcall[0] == '\0')
329
	    REprintf(_("Warning: %s\n"), buf);
329
	    REprintf(_("Warning: %s\n"), buf);
330
#ifdef SUPPORT_MBCS
330
#ifdef SUPPORT_MBCS
331
	else if(mbcslocale &&
331
	else if(mbcslocale &&
332
		18 + wd(dcall) + wd(buf) <= LONGWARN)
332
		18 + wd(dcall) + wd(buf) <= LONGWARN)
333
	    REprintf(_("Warning in %s : %s\n"), dcall, buf);
333
	    REprintf(_("Warning in %s : %s\n"), dcall, buf);
334
#endif
334
#endif
335
	else if(18+strlen(dcall)+strlen(buf) <= LONGWARN)
335
	else if(18+strlen(dcall)+strlen(buf) <= LONGWARN)
336
	    REprintf(_("Warning in %s : %s\n"), dcall, buf);
336
	    REprintf(_("Warning in %s : %s\n"), dcall, buf);
337
	else
337
	else
338
	    REprintf(_("Warning in %s :\n  %s\n"), dcall, buf);
338
	    REprintf(_("Warning in %s :\n  %s\n"), dcall, buf);
339
	if(R_ShowWarnCalls && call != R_NilValue) {
339
	if(R_ShowWarnCalls && call != R_NilValue) {
340
	    tr = R_ConciseTraceback(call, 0);
340
	    tr = R_ConciseTraceback(call, 0);
341
	    if (strlen(tr)) REprintf("Calls: %s\n", tr);
341
	    if (strlen(tr)) REprintf("Calls: %s\n", tr);
342
	}
342
	}
343
    }
343
    }
344
    else if(w == 0) {	/* collect them */
344
    else if(w == 0) {	/* collect them */
345
	char *tr; int nc; 
345
	char *tr; int nc; 
346
	if(!R_CollectWarnings)
346
	if(!R_CollectWarnings)
347
	    setupwarnings();
347
	    setupwarnings();
348
	if( R_CollectWarnings > 49 )
348
	if( R_CollectWarnings > 49 )
349
	    return;
349
	    return;
350
	SET_VECTOR_ELT(R_Warnings, R_CollectWarnings, call);
350
	SET_VECTOR_ELT(R_Warnings, R_CollectWarnings, call);
351
	Rvsnprintf(buf, min(BUFSIZE, R_WarnLength+1), format, ap);
351
	Rvsnprintf(buf, min(BUFSIZE, R_WarnLength+1), format, ap);
352
	if(R_WarnLength < BUFSIZE - 20 && strlen(buf) == R_WarnLength)
352
	if(R_WarnLength < BUFSIZE - 20 && strlen(buf) == R_WarnLength)
353
	    strcat(buf, " [... truncated]");
353
	    strcat(buf, " [... truncated]");
354
	if(R_ShowWarnCalls && call != R_NilValue) {
354
	if(R_ShowWarnCalls && call != R_NilValue) {
355
	    tr =  R_ConciseTraceback(call, 0); nc = strlen(tr);
355
	    tr =  R_ConciseTraceback(call, 0); nc = strlen(tr);
356
	    if (nc && nc + strlen(buf) + 8 < BUFSIZE) {
356
	    if (nc && nc + strlen(buf) + 8 < BUFSIZE) {
357
		strcat(buf, "\nCalls: "); 
357
		strcat(buf, "\nCalls: "); 
358
		strcat(buf, tr);
358
		strcat(buf, tr);
359
	    }
359
	    }
360
	}
360
	}
361
	names = CAR(ATTRIB(R_Warnings));
361
	names = CAR(ATTRIB(R_Warnings));
362
	SET_STRING_ELT(names, R_CollectWarnings++, mkChar(buf));
362
	SET_STRING_ELT(names, R_CollectWarnings++, mkChar(buf));
363
    }
363
    }
364
    /* else:  w <= -1 */
364
    /* else:  w <= -1 */
365
    endcontext(&cntxt);
365
    endcontext(&cntxt);
366
    inWarning = 0;
366
    inWarning = 0;
367
}
367
}
368
 
368
 
369
static void warningcall_dflt(SEXP call, const char *format,...)
369
static void warningcall_dflt(SEXP call, const char *format,...)
370
{
370
{
371
    va_list(ap);
371
    va_list(ap);
372
 
372
 
373
    va_start(ap, format);
373
    va_start(ap, format);
374
    vwarningcall_dflt(call, format, ap);
374
    vwarningcall_dflt(call, format, ap);
375
    va_end(ap);
375
    va_end(ap);
376
}
376
}
377
 
377
 
378
void warningcall(SEXP call, const char *format, ...)
378
void warningcall(SEXP call, const char *format, ...)
379
{
379
{
380
    va_list(ap);
380
    va_list(ap);
381
    va_start(ap, format);
381
    va_start(ap, format);
382
    vsignalWarning(call, format, ap);
382
    vsignalWarning(call, format, ap);
383
    va_end(ap);
383
    va_end(ap);
384
}
384
}
385
 
385
 
386
void warningcall_immediate(SEXP call, const char *format, ...)
386
void warningcall_immediate(SEXP call, const char *format, ...)
387
{
387
{
388
    va_list(ap);
388
    va_list(ap);
389
 
389
 
390
    immediateWarning = 1;
390
    immediateWarning = 1;
391
    va_start(ap, format);
391
    va_start(ap, format);
392
    vwarningcall_dflt(call, format, ap);
392
    vwarningcall_dflt(call, format, ap);
393
    va_end(ap);
393
    va_end(ap);
394
    immediateWarning = 0;
394
    immediateWarning = 0;
395
}
395
}
396
 
396
 
397
static void cleanup_PrintWarnings(void *data)
397
static void cleanup_PrintWarnings(void *data)
398
{
398
{
399
    if (R_CollectWarnings) {
399
    if (R_CollectWarnings) {
400
	R_CollectWarnings = 0;
400
	R_CollectWarnings = 0;
401
	R_Warnings = R_NilValue;
401
	R_Warnings = R_NilValue;
402
	REprintf(_("Lost warning messages\n"));
402
	REprintf(_("Lost warning messages\n"));
403
    }
403
    }
404
    inPrintWarnings = 0;
404
    inPrintWarnings = 0;
405
}
405
}
406
 
406
 
407
void PrintWarnings(void)
407
void PrintWarnings(void)
408
{
408
{
409
    int i;
409
    int i;
410
    char *header;
410
    char *header;
411
    SEXP names, s, t;
411
    SEXP names, s, t;
412
    RCNTXT cntxt;
412
    RCNTXT cntxt;
413
 
413
 
414
    if (R_CollectWarnings == 0)
414
    if (R_CollectWarnings == 0)
415
	return;
415
	return;
416
    else if (inPrintWarnings) {
416
    else if (inPrintWarnings) {
417
	if (R_CollectWarnings) {
417
	if (R_CollectWarnings) {
418
	    R_CollectWarnings = 0;
418
	    R_CollectWarnings = 0;
419
	    R_Warnings = R_NilValue;
419
	    R_Warnings = R_NilValue;
420
	    REprintf(_("Lost warning messages\n"));
420
	    REprintf(_("Lost warning messages\n"));
421
	}
421
	}
422
	return;
422
	return;
423
    }
423
    }
424
 
424
 
425
    /* set up a context which will restore inPrintWarnings if there is
425
    /* set up a context which will restore inPrintWarnings if there is
426
       an exit */
426
       an exit */
427
    begincontext(&cntxt, CTXT_CCODE, R_NilValue, R_BaseEnv, R_BaseEnv,
427
    begincontext(&cntxt, CTXT_CCODE, R_NilValue, R_BaseEnv, R_BaseEnv,
428
		 R_NilValue, R_NilValue);
428
		 R_NilValue, R_NilValue);
429
    cntxt.cend = &cleanup_PrintWarnings;
429
    cntxt.cend = &cleanup_PrintWarnings;
430
 
430
 
431
    inPrintWarnings = 1;
431
    inPrintWarnings = 1;
432
    header = P_("Warning message:\n", "Warning messages:\n", R_CollectWarnings);
432
    header = P_("Warning message:\n", "Warning messages:\n", R_CollectWarnings);
433
    if( R_CollectWarnings == 1 ) {
433
    if( R_CollectWarnings == 1 ) {
434
	REprintf("%s", header);
434
	REprintf("%s", header);
435
	names = CAR(ATTRIB(R_Warnings));
435
	names = CAR(ATTRIB(R_Warnings));
436
	if( VECTOR_ELT(R_Warnings, 0) == R_NilValue )
436
	if( VECTOR_ELT(R_Warnings, 0) == R_NilValue )
437
	   REprintf("%s \n", CHAR(STRING_ELT(names, 0)));
437
	   REprintf("%s \n", CHAR(STRING_ELT(names, 0)));
438
	else {
438
	else {
439
	    const char *dcall, *sep = " ", *msg = CHAR(STRING_ELT(names, 0));
439
	    const char *dcall, *sep = " ", *msg = CHAR(STRING_ELT(names, 0));
440
	    dcall = CHAR(STRING_ELT(deparse1(VECTOR_ELT(R_Warnings, 0),
440
	    dcall = CHAR(STRING_ELT(deparse1(VECTOR_ELT(R_Warnings, 0),
441
					     0, DEFAULTDEPARSE), 0));
441
					     0, DEFAULTDEPARSE), 0));
442
#ifdef SUPPORT_MBCS
442
#ifdef SUPPORT_MBCS
443
	    if (mbcslocale) {
443
	    if (mbcslocale) {
444
		int msgline1;
444
		int msgline1;
445
		char *p = strchr(msg, '\n');
445
		char *p = strchr(msg, '\n');
446
		if (p) {
446
		if (p) {
447
		    *p = '\0';
447
		    *p = '\0';
448
		    msgline1 = wd(msg);
448
		    msgline1 = wd(msg);
449
		    *p = '\n';
449
		    *p = '\n';
450
		} else msgline1 = wd(msg);
450
		} else msgline1 = wd(msg);
451
		if (6 + wd(dcall) + msgline1 > LONGWARN) sep = "\n  ";
451
		if (6 + wd(dcall) + msgline1 > LONGWARN) sep = "\n  ";
452
	    } else
452
	    } else
453
#endif
453
#endif
454
	    {
454
	    {
455
		int msgline1 = strlen(msg);
455
		int msgline1 = strlen(msg);
456
		char *p = strchr(msg, '\n');
456
		char *p = strchr(msg, '\n');
457
		if (p) msgline1 = (int)(p - msg);
457
		if (p) msgline1 = (int)(p - msg);
458
		if (6+strlen(dcall) + msgline1 > LONGWARN) sep = "\n  ";
458
		if (6+strlen(dcall) + msgline1 > LONGWARN) sep = "\n  ";
459
	    }
459
	    }
460
	    REprintf("In %s :%s%s\n", dcall, sep, msg);
460
	    REprintf("In %s :%s%s\n", dcall, sep, msg);
461
	}
461
	}
462
    } else if( R_CollectWarnings <= 10 ) {
462
    } else if( R_CollectWarnings <= 10 ) {
463
	REprintf("%s", header);
463
	REprintf("%s", header);
464
	names = CAR(ATTRIB(R_Warnings));
464
	names = CAR(ATTRIB(R_Warnings));
465
	for(i = 0; i < R_CollectWarnings; i++) {
465
	for(i = 0; i < R_CollectWarnings; i++) {
466
	    if( VECTOR_ELT(R_Warnings, i) == R_NilValue )
466
	    if( VECTOR_ELT(R_Warnings, i) == R_NilValue )
467
		REprintf("%d: %s \n", i+1, CHAR(STRING_ELT(names, i)));
467
		REprintf("%d: %s \n", i+1, CHAR(STRING_ELT(names, i)));
468
	    else {
468
	    else {
469
		const char *dcall, *sep = " ", *msg = CHAR(STRING_ELT(names, i));
469
		const char *dcall, *sep = " ", *msg = CHAR(STRING_ELT(names, i));
470
		dcall = CHAR(STRING_ELT(deparse1(VECTOR_ELT(R_Warnings, i),
470
		dcall = CHAR(STRING_ELT(deparse1(VECTOR_ELT(R_Warnings, i),
471
						 0, DEFAULTDEPARSE), 0));
471
						 0, DEFAULTDEPARSE), 0));
472
#ifdef SUPPORT_MBCS
472
#ifdef SUPPORT_MBCS
473
		if (mbcslocale) {
473
		if (mbcslocale) {
474
		    int msgline1;
474
		    int msgline1;
475
		    char *p = strchr(msg, '\n');
475
		    char *p = strchr(msg, '\n');
476
		    if (p) {
476
		    if (p) {
477
			*p = '\0';
477
			*p = '\0';
478
			msgline1 = wd(msg);
478
			msgline1 = wd(msg);
479
			*p = '\n';
479
			*p = '\n';
480
		    } else msgline1 = wd(msg);
480
		    } else msgline1 = wd(msg);
481
		    if (10 + wd(dcall) + msgline1 > LONGWARN) sep = "\n  ";
481
		    if (10 + wd(dcall) + msgline1 > LONGWARN) sep = "\n  ";
482
		} else
482
		} else
483
#endif
483
#endif
484
		{
484
		{
485
		    int msgline1 = strlen(msg);
485
		    int msgline1 = strlen(msg);
486
		    char *p = strchr(msg, '\n');
486
		    char *p = strchr(msg, '\n');
487
		    if (p) msgline1 = (int)(p - msg);
487
		    if (p) msgline1 = (int)(p - msg);
488
		    if (10+strlen(dcall) + msgline1 > LONGWARN) sep = "\n  ";
488
		    if (10+strlen(dcall) + msgline1 > LONGWARN) sep = "\n  ";
489
		}
489
		}
490
		REprintf("%d: In %s :%s%s\n", i+1, dcall, sep, msg);
490
		REprintf("%d: In %s :%s%s\n", i+1, dcall, sep, msg);
491
	    }
491
	    }
492
	}
492
	}
493
    } else {
493
    } else {
494
	if (R_CollectWarnings < 50)
494
	if (R_CollectWarnings < 50)
495
	    REprintf(_("There were %d warnings (use warnings() to see them)\n"),
495
	    REprintf(_("There were %d warnings (use warnings() to see them)\n"),
496
		     R_CollectWarnings);
496
		     R_CollectWarnings);
497
	else
497
	else
498
	    REprintf(_("There were 50 or more warnings (use warnings() to see the first 50)\n"));
498
	    REprintf(_("There were 50 or more warnings (use warnings() to see the first 50)\n"));
499
    }
499
    }
500
    /* now truncate and install last.warning */
500
    /* now truncate and install last.warning */
501
    PROTECT(s = allocVector(VECSXP, R_CollectWarnings));
501
    PROTECT(s = allocVector(VECSXP, R_CollectWarnings));
502
    PROTECT(t = allocVector(STRSXP, R_CollectWarnings));
502
    PROTECT(t = allocVector(STRSXP, R_CollectWarnings));
503
    names = CAR(ATTRIB(R_Warnings));
503
    names = CAR(ATTRIB(R_Warnings));
504
    for(i = 0; i < R_CollectWarnings; i++) {
504
    for(i = 0; i < R_CollectWarnings; i++) {
505
	SET_VECTOR_ELT(s, i, VECTOR_ELT(R_Warnings, i));
505
	SET_VECTOR_ELT(s, i, VECTOR_ELT(R_Warnings, i));
506
	SET_STRING_ELT(t, i, STRING_ELT(names, i));
506
	SET_STRING_ELT(t, i, STRING_ELT(names, i));
507
    }
507
    }
508
    setAttrib(s, R_NamesSymbol, t);
508
    setAttrib(s, R_NamesSymbol, t);
509
    SET_SYMVALUE(install("last.warning"), s);
509
    SET_SYMVALUE(install("last.warning"), s);
510
    UNPROTECT(2);
510
    UNPROTECT(2);
511
 
511
 
512
    endcontext(&cntxt);
512
    endcontext(&cntxt);
513
 
513
 
514
    inPrintWarnings = 0;
514
    inPrintWarnings = 0;
515
    R_CollectWarnings = 0;
515
    R_CollectWarnings = 0;
516
    R_Warnings = R_NilValue;
516
    R_Warnings = R_NilValue;
517
    return;
517
    return;
518
}
518
}
519
 
519
 
520
static char errbuf[BUFSIZE];
520
static char errbuf[BUFSIZE];
521
 
521
 
522
/* temporary hook to allow experimenting with alternate error mechanisms */
522
/* temporary hook to allow experimenting with alternate error mechanisms */
523
static void (*R_ErrorHook)(SEXP, char *) = NULL;
523
static void (*R_ErrorHook)(SEXP, char *) = NULL;
524
 
524
 
525
static void restore_inError(void *data)
525
static void restore_inError(void *data)
526
{
526
{
527
    int *poldval = (int *) data;
527
    int *poldval = (int *) data;
528
    inError = *poldval;
528
    inError = *poldval;
529
    R_Expressions = R_Expressions_keep;
529
    R_Expressions = R_Expressions_keep;
530
}
530
}
531
 
531
 
532
static void verrorcall_dflt(SEXP call, const char *format, va_list ap)
532
static void verrorcall_dflt(SEXP call, const char *format, va_list ap)
533
{
533
{
534
    RCNTXT cntxt;
534
    RCNTXT cntxt;
535
    const char *dcall;
535
    const char *dcall;
536
    char *p, *tr;
536
    char *p, *tr;
537
    int oldInError, nc;
537
    int oldInError, nc;
538
 
538
 
539
    if (inError) {
539
    if (inError) {
540
	/* fail-safe handler for recursive errors */
540
	/* fail-safe handler for recursive errors */
541
	if(inError == 3) {
541
	if(inError == 3) {
542
	     /* Can REprintf generate an error? If so we should guard for it */
542
	     /* Can REprintf generate an error? If so we should guard for it */
543
	    REprintf(_("Error during wrapup: "));
543
	    REprintf(_("Error during wrapup: "));
544
	    /* this does NOT try to print the call since that could
544
	    /* this does NOT try to print the call since that could
545
               cause a cascade of error calls */
545
               cause a cascade of error calls */
546
	    Rvsnprintf(errbuf, sizeof(errbuf), format, ap);
546
	    Rvsnprintf(errbuf, sizeof(errbuf), format, ap);
547
	    REprintf("%s\n", errbuf);
547
	    REprintf("%s\n", errbuf);
548
	}
548
	}
549
	if (R_Warnings != R_NilValue) {
549
	if (R_Warnings != R_NilValue) {
550
	    R_CollectWarnings = 0;
550
	    R_CollectWarnings = 0;
551
	    R_Warnings = R_NilValue;
551
	    R_Warnings = R_NilValue;
552
	    REprintf(_("Lost warning messages\n"));
552
	    REprintf(_("Lost warning messages\n"));
553
	}
553
	}
554
	R_Expressions = R_Expressions_keep;
554
	R_Expressions = R_Expressions_keep;
555
	jump_to_top_ex(FALSE, FALSE, FALSE, FALSE, FALSE);
555
	jump_to_top_ex(FALSE, FALSE, FALSE, FALSE, FALSE);
556
    }
556
    }
557
 
557
 
558
    /* set up a context to restore inError value on exit */
558
    /* set up a context to restore inError value on exit */
559
    begincontext(&cntxt, CTXT_CCODE, R_NilValue, R_BaseEnv, R_BaseEnv,
559
    begincontext(&cntxt, CTXT_CCODE, R_NilValue, R_BaseEnv, R_BaseEnv,
560
		 R_NilValue, R_NilValue);
560
		 R_NilValue, R_NilValue);
561
    cntxt.cend = &restore_inError;
561
    cntxt.cend = &restore_inError;
562
    cntxt.cenddata = &oldInError;
562
    cntxt.cenddata = &oldInError;
563
    oldInError = inError;
563
    oldInError = inError;
564
    inError = 1;
564
    inError = 1;
565
 
565
 
566
    if(call != R_NilValue) {
566
    if(call != R_NilValue) {
567
	char tmp[BUFSIZE];
567
	char tmp[BUFSIZE];
568
	char *head = _("Error in "), *mid = " : ", *tail = "\n  ";
568
	char *head = _("Error in "), *mid = " : ", *tail = "\n  ";
569
	int len = strlen(head) + strlen(mid) + strlen(tail);
569
	int len = strlen(head) + strlen(mid) + strlen(tail);
570
 
570
 
571
	Rvsnprintf(tmp, min(BUFSIZE, R_WarnLength) - strlen(head), format, ap);
571
	Rvsnprintf(tmp, min(BUFSIZE, R_WarnLength) - strlen(head), format, ap);
572
	dcall = CHAR(STRING_ELT(deparse1(call, 0, DEFAULTDEPARSE), 0));
572
	dcall = CHAR(STRING_ELT(deparse1(call, 0, DEFAULTDEPARSE), 0));
573
	if (len + strlen(dcall) + strlen(tmp) < BUFSIZE) {
573
	if (len + strlen(dcall) + strlen(tmp) < BUFSIZE) {
574
	    sprintf(errbuf, "%s%s%s", head, dcall, mid);
574
	    sprintf(errbuf, "%s%s%s", head, dcall, mid);
575
#ifdef SUPPORT_MBCS
575
#ifdef SUPPORT_MBCS
576
	    if (mbcslocale) {
576
	    if (mbcslocale) {
577
		int msgline1;
577
		int msgline1;
578
		char *p = strchr(tmp, '\n');
578
		char *p = strchr(tmp, '\n');
579
		if (p) {
579
		if (p) {
580
		    *p = '\0';
580
		    *p = '\0';
581
		    msgline1 = wd(tmp);
581
		    msgline1 = wd(tmp);
582
		    *p = '\n';
582
		    *p = '\n';
583
		} else msgline1 = wd(tmp);
583
		} else msgline1 = wd(tmp);
584
		if (14 + wd(dcall) + wd(tmp) > LONGWARN) strcat(errbuf, tail);
584
		if (14 + wd(dcall) + wd(tmp) > LONGWARN) strcat(errbuf, tail);
585
	    } else
585
	    } else
586
#endif
586
#endif
587
	    {
587
	    {
588
		int msgline1 = strlen(tmp);
588
		int msgline1 = strlen(tmp);
589
		char *p = strchr(tmp, '\n');
589
		char *p = strchr(tmp, '\n');
590
		if (p) msgline1 = (int)(p - tmp);
590
		if (p) msgline1 = (int)(p - tmp);
591
		if (14 + strlen(dcall) + msgline1 > LONGWARN)
591
		if (14 + strlen(dcall) + msgline1 > LONGWARN)
592
		    strcat(errbuf, tail);
592
		    strcat(errbuf, tail);
593
	    }
593
	    }
594
	    strcat(errbuf, tmp);
594
	    strcat(errbuf, tmp);
595
	} else {
595
	} else {
596
	    sprintf(errbuf, _("Error: "));
596
	    sprintf(errbuf, _("Error: "));
597
	    strcat(errbuf, tmp);
597
	    strcat(errbuf, tmp);
598
	}
598
	}
599
    }
599
    }
600
    else {
600
    else {
601
	sprintf(errbuf, _("Error: "));
601
	sprintf(errbuf, _("Error: "));
602
	p = errbuf + strlen(errbuf);
602
	p = errbuf + strlen(errbuf);
603
	Rvsnprintf(p, min(BUFSIZE, R_WarnLength) - strlen(errbuf), format, ap);
603
	Rvsnprintf(p, min(BUFSIZE, R_WarnLength) - strlen(errbuf), format, ap);
604
    }
604
    }
605
    
605
    
606
    p = errbuf + strlen(errbuf) - 1;
606
    p = errbuf + strlen(errbuf) - 1;
607
    if(*p != '\n') strcat(errbuf, "\n");
607
    if(*p != '\n') strcat(errbuf, "\n");
608
 
608
 
609
    if(R_ShowErrorCalls && call != R_NilValue) {  /* assume we want to avoid deparse */
609
    if(R_ShowErrorCalls && call != R_NilValue) {  /* assume we want to avoid deparse */
610
	tr = R_ConciseTraceback(call, 0); nc = strlen(tr);
610
	tr = R_ConciseTraceback(call, 0); nc = strlen(tr);
611
	if (nc && nc + strlen(errbuf) + 8 < BUFSIZE) {
611
	if (nc && nc + strlen(errbuf) + 8 < BUFSIZE) {
612
	    strcat(errbuf, "Calls: ");
612
	    strcat(errbuf, "Calls: ");
613
	    strcat(errbuf, tr);
613
	    strcat(errbuf, tr);
614
	    strcat(errbuf, "\n");
614
	    strcat(errbuf, "\n");
615
	}
615
	}
616
    }
616
    }
617
    if (R_ShowErrorMessages) REprintf("%s", errbuf);
617
    if (R_ShowErrorMessages) REprintf("%s", errbuf);
618
 
618
 
619
    if( R_ShowErrorMessages && R_CollectWarnings ) {
619
    if( R_ShowErrorMessages && R_CollectWarnings ) {
620
	REprintf(_("In addition: "));
620
	REprintf(_("In addition: "));
621
	PrintWarnings();
621
	PrintWarnings();
622
    }
622
    }
623
 
623
 
624
    jump_to_top_ex(TRUE, TRUE, TRUE, TRUE, FALSE);
624
    jump_to_top_ex(TRUE, TRUE, TRUE, TRUE, FALSE);
625
 
625
 
626
    /* not reached */
626
    /* not reached */
627
    endcontext(&cntxt);
627
    endcontext(&cntxt);
628
    inError = oldInError;
628
    inError = oldInError;
629
}
629
}
630
 
630
 
631
static void errorcall_dflt(SEXP call, const char *format,...)
631
static void errorcall_dflt(SEXP call, const char *format,...)
632
{
632
{
633
    va_list(ap);
633
    va_list(ap);
634
 
634
 
635
    va_start(ap, format);
635
    va_start(ap, format);
636
    verrorcall_dflt(call, format, ap);
636
    verrorcall_dflt(call, format, ap);
637
    va_end(ap);
637
    va_end(ap);
638
}
638
}
639
 
639
 
640
void errorcall(SEXP call, const char *format,...)
640
void errorcall(SEXP call, const char *format,...)
641
{
641
{
642
    va_list(ap);
642
    va_list(ap);
643
 
643
 
644
    va_start(ap, format);
644
    va_start(ap, format);
645
    vsignalError(call, format, ap);
645
    vsignalError(call, format, ap);
646
    va_end(ap);
646
    va_end(ap);
647
 
647
 
648
    if (R_ErrorHook != NULL) {
648
    if (R_ErrorHook != NULL) {
649
	char buf[BUFSIZE];
649
	char buf[BUFSIZE];
650
	void (*hook)(SEXP, char *) = R_ErrorHook;
650
	void (*hook)(SEXP, char *) = R_ErrorHook;
651
	R_ErrorHook = NULL; /* to avoid recursion */
651
	R_ErrorHook = NULL; /* to avoid recursion */
652
	va_start(ap, format);
652
	va_start(ap, format);
653
	Rvsnprintf(buf, min(BUFSIZE, R_WarnLength), format, ap);
653
	Rvsnprintf(buf, min(BUFSIZE, R_WarnLength), format, ap);
654
	va_end(ap);
654
	va_end(ap);
655
	hook(call, buf);
655
	hook(call, buf);
656
    }
656
    }
657
 
657
 
658
    va_start(ap, format);
658
    va_start(ap, format);
659
    verrorcall_dflt(call, format, ap);
659
    verrorcall_dflt(call, format, ap);
660
    va_end(ap);
660
    va_end(ap);
661
}
661
}
662
 
662
 
663
SEXP attribute_hidden do_geterrmessage(SEXP call, SEXP op, SEXP args, SEXP env)
663
SEXP attribute_hidden do_geterrmessage(SEXP call, SEXP op, SEXP args, SEXP env)
664
{
664
{
665
    SEXP res;
665
    SEXP res;
666
 
666
 
667
    checkArity(op, args);
667
    checkArity(op, args);
668
    PROTECT(res = allocVector(STRSXP, 1));
668
    PROTECT(res = allocVector(STRSXP, 1));
669
    SET_STRING_ELT(res, 0, mkChar(errbuf));
669
    SET_STRING_ELT(res, 0, mkChar(errbuf));
670
    UNPROTECT(1);
670
    UNPROTECT(1);
671
    return res;
671
    return res;
672
}
672
}
673
 
673
 
674
void error(const char *format, ...)
674
void error(const char *format, ...)
675
{
675
{
676
    char buf[BUFSIZE];
676
    char buf[BUFSIZE];
677
    RCNTXT *c = R_GlobalContext;
677
    RCNTXT *c = R_GlobalContext;
678
 
678
 
679
    va_list(ap);
679
    va_list(ap);
680
    va_start(ap, format);
680
    va_start(ap, format);
681
    Rvsnprintf(buf, min(BUFSIZE, R_WarnLength), format, ap);
681
    Rvsnprintf(buf, min(BUFSIZE, R_WarnLength), format, ap);
682
    va_end(ap);
682
    va_end(ap);
683
    /* This can be called before R_GlobalContext is defined, so... */
683
    /* This can be called before R_GlobalContext is defined, so... */
684
    /* If profiling is on, this can be a CTXT_BUILTIN */
684
    /* If profiling is on, this can be a CTXT_BUILTIN */
685
    if (c && (c->callflag & CTXT_BUILTIN)) c = c->nextcontext;
685
    if (c && (c->callflag & CTXT_BUILTIN)) c = c->nextcontext;
686
    errorcall(c ? c->call : R_NilValue, "%s", buf);
686
    errorcall(c ? c->call : R_NilValue, "%s", buf);
687
}
687
}
688
 
688
 
689
static void try_jump_to_restart(void)
689
static void try_jump_to_restart(void)
690
{
690
{
691
    SEXP list;
691
    SEXP list;
692
 
692
 
693
    for (list = R_RestartStack; list != R_NilValue; list = CDR(list)) {
693
    for (list = R_RestartStack; list != R_NilValue; list = CDR(list)) {
694
	SEXP restart = CAR(list);
694
	SEXP restart = CAR(list);
695
	if (TYPEOF(restart) == VECSXP && LENGTH(restart) > 1) {
695
	if (TYPEOF(restart) == VECSXP && LENGTH(restart) > 1) {
696
	    SEXP name = VECTOR_ELT(restart, 0);
696
	    SEXP name = VECTOR_ELT(restart, 0);
697
	    if (TYPEOF(name) == STRSXP && LENGTH(name) == 1) {
697
	    if (TYPEOF(name) == STRSXP && LENGTH(name) == 1) {
698
		const char *cname = CHAR(STRING_ELT(name, 0));
698
		const char *cname = CHAR(STRING_ELT(name, 0));
699
		if (! strcmp(cname, "browser") ||
699
		if (! strcmp(cname, "browser") ||
700
		    ! strcmp(cname, "tryRestart") ||
700
		    ! strcmp(cname, "tryRestart") ||
701
		    ! strcmp(cname, "abort")) /**** move abort eventually? */
701
		    ! strcmp(cname, "abort")) /**** move abort eventually? */
702
		    invokeRestart(restart, R_NilValue);
702
		    invokeRestart(restart, R_NilValue);
703
	    }
703
	    }
704
	}
704
	}
705
    }
705
    }
706
}
706
}
707
 
707
 
708
/* Unwind the call stack in an orderly fashion */
708
/* Unwind the call stack in an orderly fashion */
709
/* calling the code installed by on.exit along the way */
709
/* calling the code installed by on.exit along the way */
710
/* and finally longjmping to the innermost TOPLEVEL context */
710
/* and finally longjmping to the innermost TOPLEVEL context */
711
 
711
 
712
static void jump_to_top_ex(Rboolean traceback,
712
static void jump_to_top_ex(Rboolean traceback,
713
			   Rboolean tryUserHandler,
713
			   Rboolean tryUserHandler,
714
			   Rboolean processWarnings,
714
			   Rboolean processWarnings,
715
			   Rboolean resetConsole,
715
			   Rboolean resetConsole,
716
			   Rboolean ignoreRestartContexts)
716
			   Rboolean ignoreRestartContexts)
717
{
717
{
718
    RCNTXT cntxt;
718
    RCNTXT cntxt;
719
    SEXP s;
719
    SEXP s;
720
    int haveHandler, oldInError;
720
    int haveHandler, oldInError;
721
 
721
 
722
    /* set up a context to restore inError value on exit */
722
    /* set up a context to restore inError value on exit */
723
    begincontext(&cntxt, CTXT_CCODE, R_NilValue, R_BaseEnv, R_BaseEnv,
723
    begincontext(&cntxt, CTXT_CCODE, R_NilValue, R_BaseEnv, R_BaseEnv,
724
		 R_NilValue, R_NilValue);
724
		 R_NilValue, R_NilValue);
725
    cntxt.cend = &restore_inError;
725
    cntxt.cend = &restore_inError;
726
    cntxt.cenddata = &oldInError;
726
    cntxt.cenddata = &oldInError;
727
 
727
 
728
    oldInError = inError;
728
    oldInError = inError;
729
 
729
 
730
    haveHandler = FALSE;
730
    haveHandler = FALSE;
731
 
731
 
732
    if (tryUserHandler && inError < 3) {
732
    if (tryUserHandler && inError < 3) {
733
	if (! inError)
733
	if (! inError)
734
	    inError = 1;
734
	    inError = 1;
735
 
735
 
736
	/*now see if options("error") is set */
736
	/*now see if options("error") is set */
737
	s = GetOption(install("error"), R_BaseEnv);
737
	s = GetOption(install("error"), R_BaseEnv);
738
	haveHandler = ( s != R_NilValue );
738
	haveHandler = ( s != R_NilValue );
739
	if (haveHandler) {
739
	if (haveHandler) {
740
	    if( !isLanguage(s) &&  ! isExpression(s) )  /* shouldn't happen */
740
	    if( !isLanguage(s) &&  ! isExpression(s) )  /* shouldn't happen */
741
		REprintf(_("invalid option \"error\"\n"));
741
		REprintf(_("invalid option \"error\"\n"));
742
	    else {
742
	    else {
743
		inError = 3;
743
		inError = 3;
744
		if (isLanguage(s))
744
		if (isLanguage(s))
745
		    eval(s, R_GlobalEnv);
745
		    eval(s, R_GlobalEnv);
746
		else /* expression */
746
		else /* expression */
747
		    {
747
		    {
748
			int i, n = LENGTH(s);
748
			int i, n = LENGTH(s);
749
			for (i = 0 ; i < n ; i++)
749
			for (i = 0 ; i < n ; i++)
750
			    eval(VECTOR_ELT(s, i), R_GlobalEnv);
750
			    eval(VECTOR_ELT(s, i), R_GlobalEnv);
751
		    }
751
		    }
752
		inError = oldInError;
752
		inError = oldInError;
753
	    }
753
	    }
754
	}
754
	}
755
	inError = oldInError;
755
	inError = oldInError;
756
    }
756
    }
757
 
757
 
758
    /* print warnings if there are any left to be printed */
758
    /* print warnings if there are any left to be printed */
759
    if( processWarnings && R_CollectWarnings )
759
    if( processWarnings && R_CollectWarnings )
760
	PrintWarnings();
760
	PrintWarnings();
761
 
761
 
762
    /* reset some stuff--not sure (all) this belongs here */
762
    /* reset some stuff--not sure (all) this belongs here */
763
    if (resetConsole) {
763
    if (resetConsole) {
764
	R_ResetConsole();
764
	R_ResetConsole();
765
	R_FlushConsole();
765
	R_FlushConsole();
766
	R_ClearerrConsole();
766
	R_ClearerrConsole();
767
	R_ParseError = 0;
767
	R_ParseError = 0;
768
	R_ParseErrorFile = NULL;
768
	R_ParseErrorFile = NULL;
769
	R_ParseErrorMsg[0] = '\0';	
769
	R_ParseErrorMsg[0] = '\0';	
770
    }
770
    }
771
 
771
 
772
    /*
772
    /*
773
     * Reset graphics state
773
     * Reset graphics state
774
     */
774
     */
775
    GEonExit();
775
    GEonExit();
776
 
776
 
777
    /* WARNING: If oldInError > 0 ABSOLUTELY NO ALLOCATION can be
777
    /* WARNING: If oldInError > 0 ABSOLUTELY NO ALLOCATION can be
778
       triggered after this point except whatever happens in writing
778
       triggered after this point except whatever happens in writing
779
       the traceback and R_run_onexits.  The error could be an out of
779
       the traceback and R_run_onexits.  The error could be an out of
780
       memory error and any allocation could result in an
780
       memory error and any allocation could result in an
781
       infinite-loop condition. All you can do is reset things and
781
       infinite-loop condition. All you can do is reset things and
782
       exit.  */
782
       exit.  */
783
 
783
 
784
    /* jump to a browser/try if one is on the stack */
784
    /* jump to a browser/try if one is on the stack */
785
    if (! ignoreRestartContexts)
785
    if (! ignoreRestartContexts)
786
	try_jump_to_restart();
786
	try_jump_to_restart();
787
    /* at this point, i.e. if we have not exited in
787
    /* at this point, i.e. if we have not exited in
788
       try_jump_to_restart, we are heading for R_ToplevelContext */
788
       try_jump_to_restart, we are heading for R_ToplevelContext */
789
 
789
 
790
    /* only run traceback if we are not going to bail out of a
790
    /* only run traceback if we are not going to bail out of a
791
       non-interactive session */
791
       non-interactive session */
792
    if (R_Interactive || haveHandler) {
792
    if (R_Interactive || haveHandler) {
793
	/* write traceback if requested, unless we're already doing it
793
	/* write traceback if requested, unless we're already doing it
794
	   or there is an inconsistency between inError and oldInError
794
	   or there is an inconsistency between inError and oldInError
795
	   (which should not happen) */
795
	   (which should not happen) */
796
	if (traceback && inError < 2 && inError == oldInError) {
796
	if (traceback && inError < 2 && inError == oldInError) {
797
	    inError = 2;
797
	    inError = 2;
798
	    PROTECT(s = R_GetTraceback(0));
798
	    PROTECT(s = R_GetTraceback(0));
799
	    SET_SYMVALUE(install(".Traceback"), s);
799
	    SET_SYMVALUE(install(".Traceback"), s);
800
	    /* should have been defineVar
800
	    /* should have been defineVar
801
	       setVar(install(".Traceback"), s, R_GlobalEnv); */
801
	       setVar(install(".Traceback"), s, R_GlobalEnv); */
802
	    UNPROTECT(1);
802
	    UNPROTECT(1);
803
	    inError = oldInError;
803
	    inError = oldInError;
804
	}
804
	}
805
    }
805
    }
806
 
806
 
807
    /* Run onexit/cend code for all contexts down to but not including
807
    /* Run onexit/cend code for all contexts down to but not including
808
       the jump target.  This may cause recursive calls to
808
       the jump target.  This may cause recursive calls to
809
       jump_to_top_ex, but the possible number of such recursive
809
       jump_to_top_ex, but the possible number of such recursive
810
       calls is limited since each exit function is removed before it
810
       calls is limited since each exit function is removed before it
811
       is executed.  In addition, all but the first should have
811
       is executed.  In addition, all but the first should have
812
       inError > 0.  This is not a great design because we could run
812
       inError > 0.  This is not a great design because we could run
813
       out of other resources that are on the stack (like C stack for
813
       out of other resources that are on the stack (like C stack for
814
       example).  The right thing to do is arrange to execute exit
814
       example).  The right thing to do is arrange to execute exit
815
       code *after* the LONGJMP, but that requires a more extensive
815
       code *after* the LONGJMP, but that requires a more extensive
816
       redesign of the non-local transfer of control mechanism.
816
       redesign of the non-local transfer of control mechanism.
817
       LT. */
817
       LT. */
818
    R_run_onexits(R_ToplevelContext);
818
    R_run_onexits(R_ToplevelContext);
819
 
819
 
820
    if ( !R_Interactive && !haveHandler ) {
820
    if ( !R_Interactive && !haveHandler ) {
821
	REprintf(_("Execution halted\n"));
821
	REprintf(_("Execution halted\n"));
822
	R_CleanUp(SA_NOSAVE, 1, 0); /* quit, no save, no .Last, status=1 */
822
	R_CleanUp(SA_NOSAVE, 1, 0); /* quit, no save, no .Last, status=1 */
823
    }
823
    }
824
 
824
 
825
    R_GlobalContext = R_ToplevelContext;
825
    R_GlobalContext = R_ToplevelContext;
826
    R_restore_globals(R_GlobalContext);
826
    R_restore_globals(R_GlobalContext);
827
    LONGJMP(R_ToplevelContext->cjmpbuf, 0);
827
    LONGJMP(R_ToplevelContext->cjmpbuf, 0);
828
    /* not reached */
828
    /* not reached */
829
    endcontext(&cntxt);
829
    endcontext(&cntxt);
830
    inError = oldInError;
830
    inError = oldInError;
831
}
831
}
832
 
832
 
833
void jump_to_toplevel()
833
void jump_to_toplevel()
834
{
834
{
835
    /* no traceback, no user error option; for now, warnings are
835
    /* no traceback, no user error option; for now, warnings are
836
       printed here and console is reset -- eventually these should be
836
       printed here and console is reset -- eventually these should be
837
       done after arriving at the jump target.  Now ignores
837
       done after arriving at the jump target.  Now ignores
838
       try/browser frames--it really is a jump to toplevel */
838
       try/browser frames--it really is a jump to toplevel */
839
    jump_to_top_ex(FALSE, FALSE, TRUE, TRUE, TRUE);
839
    jump_to_top_ex(FALSE, FALSE, TRUE, TRUE, TRUE);
840
}
840
}
841
 
841
 
842
/* #define DEBUG_GETTEXT 1 */
842
/* #define DEBUG_GETTEXT 1 */
843
 
843
 
844
/* gettext(domain, string) */
844
/* gettext(domain, string) */
845
SEXP attribute_hidden do_gettext(SEXP call, SEXP op, SEXP args, SEXP rho)
845
SEXP attribute_hidden do_gettext(SEXP call, SEXP op, SEXP args, SEXP rho)
846
{
846
{
847
#ifdef ENABLE_NLS
847
#ifdef ENABLE_NLS
848
    const char *domain = "";
848
    const char *domain = "";
849
    char *buf;
849
    char *buf;
850
    SEXP ans, string = CADR(args);
850
    SEXP ans, string = CADR(args);
851
    int i, n = LENGTH(string);
851
    int i, n = LENGTH(string);
852
    
852
    
853
    checkArity(op, args);
853
    checkArity(op, args);
854
    if(isNull(string) || !n) return string;
854
    if(isNull(string) || !n) return string;
855
 
855
 
856
    if(!isString(string)) errorcall(call, _("invalid '%s' value"), "string");
856
    if(!isString(string)) errorcall(call, _("invalid '%s' value"), "string");
857
 
857
 
858
    if(isNull(CAR(args))) {
858
    if(isNull(CAR(args))) {
859
	RCNTXT *cptr;
859
	RCNTXT *cptr;
860
	SEXP rho = R_BaseEnv;
860
	SEXP rho = R_BaseEnv;
861
	for (cptr = R_GlobalContext->nextcontext;
861
	for (cptr = R_GlobalContext->nextcontext;
862
	     cptr != NULL && cptr->callflag != CTXT_TOPLEVEL;
862
	     cptr != NULL && cptr->callflag != CTXT_TOPLEVEL;
863
	     cptr = cptr->nextcontext)
863
	     cptr = cptr->nextcontext)
864
	    if (cptr->callflag & CTXT_FUNCTION) {
864
	    if (cptr->callflag & CTXT_FUNCTION) {
865
		rho = cptr->cloenv;
865
		rho = cptr->cloenv;
866
		break;
866
		break;
867
	    }
867
	    }
868
	while(rho != R_EmptyEnv) {
868
	while(rho != R_EmptyEnv) {
869
	    if (rho == R_GlobalEnv) break;
869
	    if (rho == R_GlobalEnv) break;
870
	    else if (R_IsNamespaceEnv(rho)) {
870
	    else if (R_IsNamespaceEnv(rho)) {
871
		domain = translateChar(STRING_ELT(R_NamespaceEnvSpec(rho), 0));
871
		domain = translateChar(STRING_ELT(R_NamespaceEnvSpec(rho), 0));
872
		break;
872
		break;
873
	    }
873
	    }
874
	    rho = CDR(rho);
874
	    rho = CDR(rho);
875
	}
875
	}
876
	if(strlen(domain)) {
876
	if(strlen(domain)) {
877
	    buf = (char *) alloca(strlen(domain)+3);
877
	    buf = (char *) alloca(strlen(domain)+3);
878
	    R_CheckStack();
878
	    R_CheckStack();
879
	    sprintf(buf, "R-%s", domain);
879
	    sprintf(buf, "R-%s", domain);
880
	    domain = buf;
880
	    domain = buf;
881
	}
881
	}
882
    } else if(isString(CAR(args)))
882
    } else if(isString(CAR(args)))
883
	domain = translateChar(STRING_ELT(CAR(args),0));
883
	domain = translateChar(STRING_ELT(CAR(args),0));
884
    else errorcall(call, _("invalid '%s' value"), "domain");
884
    else errorcall(call, _("invalid '%s' value"), "domain");
885
 
885
 
886
    if(strlen(domain)) {
886
    if(strlen(domain)) {
887
	PROTECT(ans = allocVector(STRSXP, n));
887
	PROTECT(ans = allocVector(STRSXP, n));
888
	for(i = 0; i < n; i++) {
888
	for(i = 0; i < n; i++) {
889
	    int ihead = 0, itail = 0;
889
	    int ihead = 0, itail = 0;
890
	    const char * This = translateChar(STRING_ELT(string, i));
890
	    const char * This = translateChar(STRING_ELT(string, i));
891
	    char *tmp, *head = NULL, *tail = NULL, *p, *tr;
891
	    char *tmp, *head = NULL, *tail = NULL, *p, *tr;
892
	    tmp = (char *) alloca(strlen(This) + 1);
892
	    tmp = (char *) alloca(strlen(This) + 1);
893
	    R_CheckStack();
893
	    R_CheckStack();
894
	    strcpy(tmp, This);
894
	    strcpy(tmp, This);
895
	    /* strip leading and trailing white spaces and 
895
	    /* strip leading and trailing white spaces and 
896
	       add back after translation */
896
	       add back after translation */
897
	    for(p = tmp;
897
	    for(p = tmp;
898
		*p && (*p == ' ' || *p == '\t' || *p == '\n'); 
898
		*p && (*p == ' ' || *p == '\t' || *p == '\n'); 
899
		p++, ihead++) ;
899
		p++, ihead++) ;
900
	    if(ihead > 0) {
900
	    if(ihead > 0) {
901
		head = (char *) alloca(ihead + 1);
901
		head = (char *) alloca(ihead + 1);
902
		R_CheckStack();
902
		R_CheckStack();
903
		strncpy(head, tmp, ihead);
903
		strncpy(head, tmp, ihead);
904
		head[ihead] = '\0';
904
		head[ihead] = '\0';
905
		tmp += ihead;
905
		tmp += ihead;
906
		}
906
		}
907
	    if(strlen(tmp))
907
	    if(strlen(tmp))
908
		for(p = tmp+strlen(tmp)-1; 
908
		for(p = tmp+strlen(tmp)-1; 
909
		    p >= tmp && (*p == ' ' || *p == '\t' || *p == '\n');
909
		    p >= tmp && (*p == ' ' || *p == '\t' || *p == '\n');
910
		    p--, itail++) ;
910
		    p--, itail++) ;
911
	    if(itail > 0) {
911
	    if(itail > 0) {
912
		tail = (char *) alloca(itail + 1);
912
		tail = (char *) alloca(itail + 1);
913
		R_CheckStack();
913
		R_CheckStack();
914
		strcpy(tail, tmp+strlen(tmp)-itail);
914
		strcpy(tail, tmp+strlen(tmp)-itail);
915
		tmp[strlen(tmp)-itail] = '\0';
915
		tmp[strlen(tmp)-itail] = '\0';
916
		}
916
		}
917
	    if(strlen(tmp)) {
917
	    if(strlen(tmp)) {
918
#ifdef DEBUG_GETTEXT
918
#ifdef DEBUG_GETTEXT
919
		REprintf("translating '%s' in domain '%s'\n", tmp, domain);
919
		REprintf("translating '%s' in domain '%s'\n", tmp, domain);
920
#endif
920
#endif
921
		tr = dgettext(domain, tmp);
921
		tr = dgettext(domain, tmp);
922
		tmp = (char *) alloca(strlen(tr) + ihead + itail + 1);
922
		tmp = (char *) alloca(strlen(tr) + ihead + itail + 1);
923
		R_CheckStack();
923
		R_CheckStack();
924
		tmp[0] ='\0';
924
		tmp[0] ='\0';
925
		if(ihead > 0) strcat(tmp, head);
925
		if(ihead > 0) strcat(tmp, head);
926
		strcat(tmp, tr);
926
		strcat(tmp, tr);
927
		if(itail > 0) strcat(tmp, tail);
927
		if(itail > 0) strcat(tmp, tail);
928
		SET_STRING_ELT(ans, i, mkChar(tmp));
928
		SET_STRING_ELT(ans, i, mkChar(tmp));
929
	    } else 
929
	    } else 
930
		SET_STRING_ELT(ans, i, mkChar(This));
930
		SET_STRING_ELT(ans, i, mkChar(This));
931
	}
931
	}
932
	UNPROTECT(1);
932
	UNPROTECT(1);
933
	return ans;
933
	return ans;
934
    } else return CADR(args);
934
    } else return CADR(args);
935
#else
935
#else
936
    return CADR(args);
936
    return CADR(args);
937
#endif
937
#endif
938
}
938
}
939
 
939
 
940
/* ngettext(n, msg1, msg2, domain) */
940
/* ngettext(n, msg1, msg2, domain) */
941
SEXP attribute_hidden do_ngettext(SEXP call, SEXP op, SEXP args, SEXP rho)
941
SEXP attribute_hidden do_ngettext(SEXP call, SEXP op, SEXP args, SEXP rho)
942
{
942
{
943
#ifdef ENABLE_NLS
943
#ifdef ENABLE_NLS
944
    const char *domain = "";
944
    const char *domain = "";
945
    char *buf;
945
    char *buf;
946
    SEXP ans, sdom = CADDDR(args);
946
    SEXP ans, sdom = CADDDR(args);
947
#endif
947
#endif
948
    SEXP msg1 = CADR(args), msg2 = CADDR(args);
948
    SEXP msg1 = CADR(args), msg2 = CADDR(args);
949
    int n = asInteger(CAR(args));
949
    int n = asInteger(CAR(args));
950
    
950
    
951
    checkArity(op, args);
951
    checkArity(op, args);
952
    if(n == NA_INTEGER || n < 0) error(_("invalid 'n'"));
952
    if(n == NA_INTEGER || n < 0) error(_("invalid 'n'"));
953
    if(!isString(msg1) || LENGTH(msg1) != 1)
953
    if(!isString(msg1) || LENGTH(msg1) != 1)
954
	error(_("'msg1' must be a character string"));
954
	error(_("'msg1' must be a character string"));
955
    if(!isString(msg2) || LENGTH(msg2) != 1)
955
    if(!isString(msg2) || LENGTH(msg2) != 1)
956
	error(_("'msg2' must be a character string"));
956
	error(_("'msg2' must be a character string"));
957
 
957
 
958
#ifdef ENABLE_NLS
958
#ifdef ENABLE_NLS
959
    if(isNull(sdom)) {
959
    if(isNull(sdom)) {
960
	RCNTXT *cptr;
960
	RCNTXT *cptr;
961
	SEXP rho = R_BaseEnv;
961
	SEXP rho = R_BaseEnv;
962
	for (cptr = R_GlobalContext->nextcontext;
962
	for (cptr = R_GlobalContext->nextcontext;
963
	     cptr != NULL && cptr->callflag != CTXT_TOPLEVEL;
963
	     cptr != NULL && cptr->callflag != CTXT_TOPLEVEL;
964
	     cptr = cptr->nextcontext)
964
	     cptr = cptr->nextcontext)
965
	    if (cptr->callflag & CTXT_FUNCTION) {
965
	    if (cptr->callflag & CTXT_FUNCTION) {
966
		rho = cptr->cloenv;
966
		rho = cptr->cloenv;
967
		break;
967
		break;
968
	    }
968
	    }
969
	while(rho != R_EmptyEnv) {
969
	while(rho != R_EmptyEnv) {
970
	    if (rho == R_GlobalEnv) break;
970
	    if (rho == R_GlobalEnv) break;
971
	    else if (R_IsNamespaceEnv(rho)) {
971
	    else if (R_IsNamespaceEnv(rho)) {
972
		domain = translateChar(STRING_ELT(R_NamespaceEnvSpec(rho), 0));
972
		domain = translateChar(STRING_ELT(R_NamespaceEnvSpec(rho), 0));
973
		break;
973
		break;
974
	    }
974
	    }
975
	    rho = CDR(rho);
975
	    rho = CDR(rho);
976
	}
976
	}
977
	if(strlen(domain)) {
977
	if(strlen(domain)) {
978
	    buf = (char *) alloca(strlen(domain)+3);
978
	    buf = (char *) alloca(strlen(domain)+3);
979
	    R_CheckStack();
979
	    R_CheckStack();
980
	    sprintf(buf, "R-%s", domain);
980
	    sprintf(buf, "R-%s", domain);
981
	    domain = buf;
981
	    domain = buf;
982
	}
982
	}
983
    } else if(isString(sdom))
983
    } else if(isString(sdom))
984
	domain = CHAR(STRING_ELT(sdom,0));
984
	domain = CHAR(STRING_ELT(sdom,0));
985
    else errorcall(call, _("invalid '%s' value"), "domain");
985
    else errorcall(call, _("invalid '%s' value"), "domain");
986
 
986
 
987
    /* libintl seems to malfunction if given a message of "" */
987
    /* libintl seems to malfunction if given a message of "" */
988
    if(strlen(domain) && length(STRING_ELT(msg1, 0))) {
988
    if(strlen(domain) && length(STRING_ELT(msg1, 0))) {
989
	char *fmt = dngettext(domain,
989
	char *fmt = dngettext(domain,
990
			      translateChar(STRING_ELT(msg1, 0)),
990
			      translateChar(STRING_ELT(msg1, 0)),
991
			      translateChar(STRING_ELT(msg2, 0)),
991
			      translateChar(STRING_ELT(msg2, 0)),
992
			      n);
992
			      n);
993
	PROTECT(ans = mkString(fmt));
993
	PROTECT(ans = mkString(fmt));
994
	UNPROTECT(1);
994
	UNPROTECT(1);
995
	return ans;
995
	return ans;
996
    } else
996
    } else
997
#endif
997
#endif
998
	return n == 1 ? msg1 : msg2;
998
	return n == 1 ? msg1 : msg2;
999
}
999
}
1000
 
1000
 
1001
 
1001
 
1002
/* bindtextdomain(domain, dirname) */
1002
/* bindtextdomain(domain, dirname) */
1003
SEXP attribute_hidden do_bindtextdomain(SEXP call, SEXP op, SEXP args, SEXP rho)
1003
SEXP attribute_hidden do_bindtextdomain(SEXP call, SEXP op, SEXP args, SEXP rho)
1004
{
1004
{
1005
#ifdef ENABLE_NLS
1005
#ifdef ENABLE_NLS
1006
    char *res;
1006
    char *res;
1007
    
1007
    
1008
    checkArity(op, args);
1008
    checkArity(op, args);
1009
    if(!isString(CAR(args)) || LENGTH(CAR(args)) != 1) 
1009
    if(!isString(CAR(args)) || LENGTH(CAR(args)) != 1) 
1010
	errorcall(call, _("invalid '%s' value"), "domain");
1010
	errorcall(call, _("invalid '%s' value"), "domain");
1011
    if(isNull(CADR(args))) {
1011
    if(isNull(CADR(args))) {
1012
	res = bindtextdomain(translateChar(STRING_ELT(CAR(args),0)), NULL);
1012
	res = bindtextdomain(translateChar(STRING_ELT(CAR(args),0)), NULL);
1013
    } else {
1013
    } else {
1014
	if(!isString(CADR(args)) || LENGTH(CADR(args)) != 1) 
1014
	if(!isString(CADR(args)) || LENGTH(CADR(args)) != 1) 
1015
	    errorcall(call, _("invalid '%s' value"), "dirname");
1015
	    errorcall(call, _("invalid '%s' value"), "dirname");
1016
	res = bindtextdomain(translateChar(STRING_ELT(CAR(args),0)),
1016
	res = bindtextdomain(translateChar(STRING_ELT(CAR(args),0)),
1017
			     translateChar(STRING_ELT(CADR(args),0)));
1017
			     translateChar(STRING_ELT(CADR(args),0)));
1018
    }
1018
    }
1019
    if(res) return mkString(res);
1019
    if(res) return mkString(res);
1020
    /* else this failed */
1020
    /* else this failed */
1021
#endif
1021
#endif
1022
    return R_NilValue;
1022
    return R_NilValue;
1023
}
1023
}
1024
 
1024
 
1025
static SEXP findCall(void)
1025
static SEXP findCall(void)
1026
{
1026
{
1027
    RCNTXT *cptr;
1027
    RCNTXT *cptr;
1028
    for (cptr = R_GlobalContext->nextcontext;
1028
    for (cptr = R_GlobalContext->nextcontext;
1029
	 cptr != NULL && cptr->callflag != CTXT_TOPLEVEL;
1029
	 cptr != NULL && cptr->callflag != CTXT_TOPLEVEL;
1030
	 cptr = cptr->nextcontext)
1030
	 cptr = cptr->nextcontext)
1031
	if (cptr->callflag & CTXT_FUNCTION)
1031
	if (cptr->callflag & CTXT_FUNCTION)
1032
	    return cptr->call;
1032
	    return cptr->call;
1033
    return R_NilValue;
1033
    return R_NilValue;
1034
}
1034
}
1035
 
1035
 
1036
SEXP attribute_hidden do_stop(SEXP call, SEXP op, SEXP args, SEXP rho)
1036
SEXP attribute_hidden do_stop(SEXP call, SEXP op, SEXP args, SEXP rho)
1037
{
1037
{
1038
/* error(.) : really doesn't return anything; but all do_foo() must be SEXP */
1038
/* error(.) : really doesn't return anything; but all do_foo() must be SEXP */
1039
    SEXP c_call;
1039
    SEXP c_call;
1040
 
1040
 
1041
    if(asLogical(CAR(args))) /* find context -> "Error in ..:" */
1041
    if(asLogical(CAR(args))) /* find context -> "Error in ..:" */
1042
	c_call = findCall();
1042
	c_call = findCall();
1043
    else
1043
    else
1044
	c_call = R_NilValue;    
1044
	c_call = R_NilValue;    
1045
    
1045
    
1046
    args = CDR(args);
1046
    args = CDR(args);
1047
 
1047
 
1048
    if (CAR(args) != R_NilValue) { /* message */
1048
    if (CAR(args) != R_NilValue) { /* message */
1049
      SETCAR(args, coerceVector(CAR(args), STRSXP));
1049
      SETCAR(args, coerceVector(CAR(args), STRSXP));
1050
      if(!isValidString(CAR(args)))
1050
      if(!isValidString(CAR(args)))
1051
	  errorcall(c_call, _(" [invalid string in stop(.)]"));
1051
	  errorcall(c_call, _(" [invalid string in stop(.)]"));
1052
      errorcall(c_call, "%s", translateChar(STRING_ELT(CAR(args), 0)));
1052
      errorcall(c_call, "%s", translateChar(STRING_ELT(CAR(args), 0)));
1053
    }
1053
    }
1054
    else
1054
    else
1055
      errorcall(c_call, "");
1055
      errorcall(c_call, "");
1056
    /* never called: */return c_call;
1056
    /* never called: */return c_call;
1057
}
1057
}
1058
 
1058
 
1059
SEXP attribute_hidden do_warning(SEXP call, SEXP op, SEXP args, SEXP rho)
1059
SEXP attribute_hidden do_warning(SEXP call, SEXP op, SEXP args, SEXP rho)
1060
{
1060
{
1061
    SEXP c_call;
1061
    SEXP c_call;
1062
 
1062
 
1063
    if(asLogical(CAR(args))) /* find context -> "... in: ..:" */
1063
    if(asLogical(CAR(args))) /* find context -> "... in: ..:" */
1064
	c_call = findCall();
1064
	c_call = findCall();
1065
    else
1065
    else
1066
	c_call = R_NilValue;
1066
	c_call = R_NilValue;
1067
 
1067
 
1068
    args = CDR(args);
1068
    args = CDR(args);
1069
    if(asLogical(CAR(args))) { /* immediate = TRUE */
1069
    if(asLogical(CAR(args))) { /* immediate = TRUE */
1070
	immediateWarning = 1;
1070
	immediateWarning = 1;
1071
    } else 
1071
    } else 
1072
	immediateWarning = 0;
1072
	immediateWarning = 0;
1073
    args = CDR(args);
1073
    args = CDR(args);
1074
    if (CAR(args) != R_NilValue) {
1074
    if (CAR(args) != R_NilValue) {
1075
	SETCAR(args, coerceVector(CAR(args), STRSXP));
1075
	SETCAR(args, coerceVector(CAR(args), STRSXP));
1076
	if(!isValidString(CAR(args)))
1076
	if(!isValidString(CAR(args)))
1077
	    warningcall(c_call, _(" [invalid string in warning(.)]"));
1077
	    warningcall(c_call, _(" [invalid string in warning(.)]"));
1078
	else
1078
	else
1079
	    warningcall(c_call, "%s", translateChar(STRING_ELT(CAR(args), 0)));
1079
	    warningcall(c_call, "%s", translateChar(STRING_ELT(CAR(args), 0)));
1080
    }
1080
    }
1081
    else
1081
    else
1082
	warningcall(c_call, "");
1082
	warningcall(c_call, "");
1083
    immediateWarning = 0; /* reset to internal calls */
1083
    immediateWarning = 0; /* reset to internal calls */
1084
 
1084
 
1085
    return CAR(args);
1085
    return CAR(args);
1086
}
1086
}
1087
 
1087
 
1088
/* Error recovery for incorrect argument count error. */
1088
/* Error recovery for incorrect argument count error. */
1089
attribute_hidden
1089
attribute_hidden
1090
void WrongArgCount(const char *s)
1090
void WrongArgCount(const char *s)
1091
{
1091
{
1092
    error(_("incorrect number of arguments to \"%s\""), s);
1092
    error(_("incorrect number of arguments to \"%s\""), s);
1093
}
1093
}
1094
 
1094
 
1095
 
1095
 
1096
void UNIMPLEMENTED(const char *s)
1096
void UNIMPLEMENTED(const char *s)
1097
{
1097
{
1098
    error(_("unimplemented feature in %s"), s);
1098
    error(_("unimplemented feature in %s"), s);
1099
}
1099
}
1100
 
1100
 
1101
/* ERROR_.. codes in Errormsg.h */
1101
/* ERROR_.. codes in Errormsg.h */
1102
static struct {
1102
static struct {
1103
    const R_ERROR code;
1103
    const R_ERROR code;
1104
    const char* const format;
1104
    const char* const format;
1105
}
1105
}
1106
const ErrorDB[] = {
1106
const ErrorDB[] = {
1107
    { ERROR_NUMARGS,		N_("invalid number of arguments")	},
1107
    { ERROR_NUMARGS,		N_("invalid number of arguments")	},
1108
    { ERROR_ARGTYPE,		N_("invalid argument type")		},
1108
    { ERROR_ARGTYPE,		N_("invalid argument type")		},
1109
 
1109
 
1110
    { ERROR_TSVEC_MISMATCH,	N_("time-series/vector length mismatch")},
1110
    { ERROR_TSVEC_MISMATCH,	N_("time-series/vector length mismatch")},
1111
    { ERROR_INCOMPAT_ARGS,	N_("incompatible arguments")		},
1111
    { ERROR_INCOMPAT_ARGS,	N_("incompatible arguments")		},
1112
 
1112
 
1113
    { ERROR_UNIMPLEMENTED,	N_("unimplemented feature in %s")	},
1113
    { ERROR_UNIMPLEMENTED,	N_("unimplemented feature in %s")	},
1114
    { ERROR_UNKNOWN,		N_("unknown error (report this!)")	}
1114
    { ERROR_UNKNOWN,		N_("unknown error (report this!)")	}
1115
};
1115
};
1116
 
1116
 
1117
static struct {
1117
static struct {
1118
    R_WARNING code;
1118
    R_WARNING code;
1119
    char* format;
1119
    char* format;
1120
}
1120
}
1121
WarningDB[] = {
1121
WarningDB[] = {
1122
    { WARNING_coerce_NA,	N_("NAs introduced by coercion")	},
1122
    { WARNING_coerce_NA,	N_("NAs introduced by coercion")	},
1123
    { WARNING_coerce_INACC,	N_("inaccurate integer conversion in coercion")},
1123
    { WARNING_coerce_INACC,	N_("inaccurate integer conversion in coercion")},
1124
    { WARNING_coerce_IMAG,	N_("imaginary parts discarded in coercion") },
1124
    { WARNING_coerce_IMAG,	N_("imaginary parts discarded in coercion") },
1125
 
1125
 
1126
    { WARNING_UNKNOWN,		N_("unknown warning (report this!)")	},
1126
    { WARNING_UNKNOWN,		N_("unknown warning (report this!)")	},
1127
};
1127
};
1128
 
1128
 
1129
 
1129
 
1130
void ErrorMessage(SEXP call, int which_error, ...)
1130
void ErrorMessage(SEXP call, int which_error, ...)
1131
{
1131
{
1132
    int i;
1132
    int i;
1133
    char buf[BUFSIZE];
1133
    char buf[BUFSIZE];
1134
    va_list(ap);
1134
    va_list(ap);
1135
 
1135
 
1136
    i = 0;
1136
    i = 0;
1137
    while(ErrorDB[i].code != ERROR_UNKNOWN) {
1137
    while(ErrorDB[i].code != ERROR_UNKNOWN) {
1138
	if (ErrorDB[i].code == which_error)
1138
	if (ErrorDB[i].code == which_error)
1139
	    break;
1139
	    break;
1140
	i++;
1140
	i++;
1141
    }
1141
    }
1142
 
1142
 
1143
    va_start(ap, which_error);
1143
    va_start(ap, which_error);
1144
    Rvsnprintf(buf, BUFSIZE, _(ErrorDB[i].format), ap);
1144
    Rvsnprintf(buf, BUFSIZE, _(ErrorDB[i].format), ap);
1145
    va_end(ap);
1145
    va_end(ap);
1146
    errorcall(call, "%s", buf);
1146
    errorcall(call, "%s", buf);
1147
}
1147
}
1148
 
1148
 
1149
void WarningMessage(SEXP call, R_WARNING which_warn, ...)
1149
void WarningMessage(SEXP call, R_WARNING which_warn, ...)
1150
{
1150
{
1151
    int i;
1151
    int i;
1152
    char buf[BUFSIZE];
1152
    char buf[BUFSIZE];
1153
    va_list(ap);
1153
    va_list(ap);
1154
 
1154
 
1155
    i = 0;
1155
    i = 0;
1156
    while(WarningDB[i].code != WARNING_UNKNOWN) {
1156
    while(WarningDB[i].code != WARNING_UNKNOWN) {
1157
	if (WarningDB[i].code == which_warn)
1157
	if (WarningDB[i].code == which_warn)
1158
	    break;
1158
	    break;
1159
	i++;
1159
	i++;
1160
    }
1160
    }
1161
 
1161
 
1162
    va_start(ap, which_warn);
1162
    va_start(ap, which_warn);
1163
    Rvsnprintf(buf, BUFSIZE, _(WarningDB[i].format), ap);
1163
    Rvsnprintf(buf, BUFSIZE, _(WarningDB[i].format), ap);
1164
    va_end(ap);
1164
    va_end(ap);
1165
    warningcall(call, "%s", buf);
1165
    warningcall(call, "%s", buf);
1166
}
1166
}
1167
 
1167
 
1168
 
1168
 
1169
/* Temporary hooks to allow experimenting with alternate error and
1169
/* Temporary hooks to allow experimenting with alternate error and
1170
   warning mechanisms.  They are not in the header files for now, but
1170
   warning mechanisms.  They are not in the header files for now, but
1171
   the following snippet can serve as a header file: */
1171
   the following snippet can serve as a header file: */
1172
 
1172
 
1173
void R_ReturnOrRestart(SEXP val, SEXP env, Rboolean restart);
1173
void R_ReturnOrRestart(SEXP val, SEXP env, Rboolean restart);
1174
void R_PrintDeferredWarnings(void);
1174
void R_PrintDeferredWarnings(void);
1175
void R_SetErrmessage(const char *s);
1175
void R_SetErrmessage(const char *s);
1176
void R_SetErrorHook(void (*hook)(SEXP, char *));
1176
void R_SetErrorHook(void (*hook)(SEXP, char *));
1177
void R_SetWarningHook(void (*hook)(SEXP, char *));
1177
void R_SetWarningHook(void (*hook)(SEXP, char *));
1178
void R_JumpToToplevel(Rboolean restart);
1178
void R_JumpToToplevel(Rboolean restart);
1179
 
1179
 
1180
 
1180
 
1181
void R_SetWarningHook(void (*hook)(SEXP, char *))
1181
void R_SetWarningHook(void (*hook)(SEXP, char *))
1182
{
1182
{
1183
    R_WarningHook = hook;
1183
    R_WarningHook = hook;
1184
}
1184
}
1185
 
1185
 
1186
void R_SetErrorHook(void (*hook)(SEXP, char *))
1186
void R_SetErrorHook(void (*hook)(SEXP, char *))
1187
{
1187
{
1188
    R_ErrorHook = hook;
1188
    R_ErrorHook = hook;
1189
}
1189
}
1190
 
1190
 
1191
void R_ReturnOrRestart(SEXP val, SEXP env, Rboolean restart)
1191
void R_ReturnOrRestart(SEXP val, SEXP env, Rboolean restart)
1192
{
1192
{
1193
    int mask;
1193
    int mask;
1194
    RCNTXT *c;
1194
    RCNTXT *c;
1195
 
1195
 
1196
    mask = CTXT_BROWSER | CTXT_FUNCTION;
1196
    mask = CTXT_BROWSER | CTXT_FUNCTION;
1197
 
1197
 
1198
    for (c = R_GlobalContext; c; c = c->nextcontext) {
1198
    for (c = R_GlobalContext; c; c = c->nextcontext) {
1199
	if (c->callflag & mask && c->cloenv == env)
1199
	if (c->callflag & mask && c->cloenv == env)
1200
	    findcontext(mask, env, val);
1200
	    findcontext(mask, env, val);
1201
	else if (restart && IS_RESTART_BIT_SET(c->callflag))
1201
	else if (restart && IS_RESTART_BIT_SET(c->callflag))
1202
	    findcontext(CTXT_RESTART, c->cloenv, R_RestartToken);
1202
	    findcontext(CTXT_RESTART, c->cloenv, R_RestartToken);
1203
	else if (c->callflag == CTXT_TOPLEVEL)
1203
	else if (c->callflag == CTXT_TOPLEVEL)
1204
	    error(_("No function to return from, jumping to top level"));
1204
	    error(_("No function to return from, jumping to top level"));
1205
    }
1205
    }
1206
}
1206
}
1207
 
1207
 
1208
void R_JumpToToplevel(Rboolean restart)
1208
void R_JumpToToplevel(Rboolean restart)
1209
{
1209
{
1210
    RCNTXT *c;
1210
    RCNTXT *c;
1211
 
1211
 
1212
    /* Find the target for the jump */
1212
    /* Find the target for the jump */
1213
    for (c = R_GlobalContext; c != NULL; c = c->nextcontext) {
1213
    for (c = R_GlobalContext; c != NULL; c = c->nextcontext) {
1214
	if (restart && IS_RESTART_BIT_SET(c->callflag))
1214
	if (restart && IS_RESTART_BIT_SET(c->callflag))
1215
	    findcontext(CTXT_RESTART, c->cloenv, R_RestartToken);
1215
	    findcontext(CTXT_RESTART, c->cloenv, R_RestartToken);
1216
	else if (c->callflag == CTXT_TOPLEVEL)
1216
	else if (c->callflag == CTXT_TOPLEVEL)
1217
	    break;
1217
	    break;
1218
    }
1218
    }
1219
    if (c != R_ToplevelContext)
1219
    if (c != R_ToplevelContext)
1220
	warning(_("top level inconsistency?"));
1220
	warning(_("top level inconsistency?"));
1221
 
1221
 
1222
    /* Run onexit/cend code for everything above the target. */
1222
    /* Run onexit/cend code for everything above the target. */
1223
    R_run_onexits(c);
1223
    R_run_onexits(c);
1224
 
1224
 
1225
    R_ToplevelContext = R_GlobalContext = c;
1225
    R_ToplevelContext = R_GlobalContext = c;
1226
    R_restore_globals(R_GlobalContext);
1226
    R_restore_globals(R_GlobalContext);
1227
    LONGJMP(c->cjmpbuf, CTXT_TOPLEVEL);
1227
    LONGJMP(c->cjmpbuf, CTXT_TOPLEVEL);
1228
}
1228
}
1229
 
1229
 
1230
void R_SetErrmessage(const char *s)
1230
void R_SetErrmessage(const char *s)
1231
{
1231
{
1232
    strncpy(errbuf, s, sizeof(errbuf));
1232
    strncpy(errbuf, s, sizeof(errbuf));
1233
    errbuf[sizeof(errbuf) - 1] = 0;
1233
    errbuf[sizeof(errbuf) - 1] = 0;
1234
}
1234
}
1235
 
1235
 
1236
void R_PrintDeferredWarnings(void)
1236
void R_PrintDeferredWarnings(void)
1237
{
1237
{
1238
    if( R_ShowErrorMessages && R_CollectWarnings ) {
1238
    if( R_ShowErrorMessages && R_CollectWarnings ) {
1239
        REprintf(_("In addition: "));
1239
        REprintf(_("In addition: "));
1240
        PrintWarnings();
1240
        PrintWarnings();
1241
    }
1241
    }
1242
}
1242
}
1243
 
1243
 
1244
SEXP R_GetTraceback(int skip)
1244
SEXP R_GetTraceback(int skip)
1245
{
1245
{
1246
    int nback = 0, ns;
1246
    int nback = 0, ns;
1247
    RCNTXT *c;
1247
    RCNTXT *c;
1248
    SEXP s, t;
1248
    SEXP s, t;
1249
 
1249
 
1250
    for (c = R_GlobalContext, ns = skip;
1250
    for (c = R_GlobalContext, ns = skip;
1251
	 c != NULL && c->callflag != CTXT_TOPLEVEL;
1251
	 c != NULL && c->callflag != CTXT_TOPLEVEL;
1252
	 c = c->nextcontext)
1252
	 c = c->nextcontext)
1253
	if (c->callflag & (CTXT_FUNCTION | CTXT_BUILTIN) ) {
1253
	if (c->callflag & (CTXT_FUNCTION | CTXT_BUILTIN) ) {
1254
	    if (ns > 0)
1254
	    if (ns > 0)
1255
		ns--;
1255
		ns--;
1256
	    else
1256
	    else
1257
		nback++;
1257
		nback++;
1258
	}
1258
	}
1259
 
1259
 
1260
    PROTECT(s = allocList(nback));
1260
    PROTECT(s = allocList(nback));
1261
    t = s;
1261
    t = s;
1262
    for (c = R_GlobalContext ;
1262
    for (c = R_GlobalContext ;
1263
	 c != NULL && c->callflag != CTXT_TOPLEVEL;
1263
	 c != NULL && c->callflag != CTXT_TOPLEVEL;
1264
	 c = c->nextcontext)
1264
	 c = c->nextcontext)
1265
	if (c->callflag & (CTXT_FUNCTION | CTXT_BUILTIN) ) {
1265
	if (c->callflag & (CTXT_FUNCTION | CTXT_BUILTIN) ) {
1266
	    if (skip > 0)
1266
	    if (skip > 0)
1267
		skip--;
1267
		skip--;
1268
	    else {
1268
	    else {
1269
		SETCAR(t, deparse1(c->call, 0, DEFAULTDEPARSE));
1269
		SETCAR(t, deparse1(c->call, 0, DEFAULTDEPARSE));
1270
		t = CDR(t);
1270
		t = CDR(t);
1271
	    }
1271
	    }
1272
	}
1272
	}
1273
    UNPROTECT(1);
1273
    UNPROTECT(1);
1274
    return s;
1274
    return s;
1275
}
1275
}
1276
\
1276
\
1277
static char * R_ConciseTraceback(SEXP call, int skip)
1277
static char * R_ConciseTraceback(SEXP call, int skip)
1278
{
1278
{
1279
    static char buf[560];
1279
    static char buf[560];
1280
    RCNTXT *c;
1280
    RCNTXT *c;
1281
    int nl, ncalls = 0;
1281
    int nl, ncalls = 0;
1282
    Rboolean too_many = FALSE;
1282
    Rboolean too_many = FALSE;
1283
    const char *top = "" /* -Wall */;
1283
    const char *top = "" /* -Wall */;
1284
 
1284
 
1285
    buf[0] = '\0';
1285
    buf[0] = '\0';
1286
    for (c = R_GlobalContext;
1286
    for (c = R_GlobalContext;
1287
	 c != NULL && c->callflag != CTXT_TOPLEVEL;
1287
	 c != NULL && c->callflag != CTXT_TOPLEVEL;
1288
	 c = c->nextcontext)
1288
	 c = c->nextcontext)
1289
	if (c->callflag & (CTXT_FUNCTION | CTXT_BUILTIN) ) {
1289
	if (c->callflag & (CTXT_FUNCTION | CTXT_BUILTIN) ) {
1290
	    if (skip > 0)
1290
	    if (skip > 0)
1291
		skip--;
1291
		skip--;
1292
	    else {
1292
	    else {
1293
		SEXP fun = CAR(c->call);
1293
		SEXP fun = CAR(c->call);
1294
		const char *this = (TYPEOF(fun) == SYMSXP) ?
1294
		const char *this = (TYPEOF(fun) == SYMSXP) ?
1295
		    CHAR(PRINTNAME(fun)) : "<Anonymous>";
1295
		    CHAR(PRINTNAME(fun)) : "<Anonymous>";
1296
		if(streql(this, "stop") || 
1296
		if(streql(this, "stop") || 
1297
		   streql(this, "warning") || 
1297
		   streql(this, "warning") || 
1298
		   streql(this, "suppressWarnings") || 
1298
		   streql(this, "suppressWarnings") || 
1299
		   streql(this, ".signalSimpleWarning")) {
1299
		   streql(this, ".signalSimpleWarning")) {
1300
		    buf[0] =  '\0'; ncalls = 0; too_many = FALSE;
1300
		    buf[0] =  '\0'; ncalls = 0; too_many = FALSE;
1301
		} else {
1301
		} else {
1302
		    ncalls++;
1302
		    ncalls++;
1303
		    if(too_many) {
1303
		    if(too_many) {
1304
			top = this;
1304
			top = this;
1305
		    } else if(strlen(buf) > R_NShowCalls) {
1305
		    } else if(strlen(buf) > R_NShowCalls) {
1306
			memmove(buf+4, buf, strlen(buf)+1);
1306
			memmove(buf+4, buf, strlen(buf)+1);
1307
			memcpy(buf, "... ", 4);
1307
			memcpy(buf, "... ", 4);
1308
			too_many = TRUE;
1308
			too_many = TRUE;
1309
			top = this;
1309
			top = this;
1310
		    } else if(strlen(buf)) {
1310
		    } else if(strlen(buf)) {
1311
			nl = strlen(this);
1311
			nl = strlen(this);
1312
			memmove(buf+nl+4, buf, strlen(buf)+1);
1312
			memmove(buf+nl+4, buf, strlen(buf)+1);
1313
			memcpy(buf, this, strlen(this));
1313
			memcpy(buf, this, strlen(this));
1314
			memcpy(buf+nl, " -> ", 4);
1314
			memcpy(buf+nl, " -> ", 4);
1315
		    } else
1315
		    } else
1316
			memcpy(buf, this, strlen(this)+1);
1316
			memcpy(buf, this, strlen(this)+1);
1317
		}
1317
		}
1318
	    }
1318
	    }
1319
	}
1319
	}
1320
    if(too_many && (nl = strlen(top)) < 50) {
1320
    if(too_many && (nl = strlen(top)) < 50) {
1321
	memmove(buf+nl+1, buf, strlen(buf)+1);
1321
	memmove(buf+nl+1, buf, strlen(buf)+1);
1322
	memcpy(buf, top, strlen(top));
1322
	memcpy(buf, top, strlen(top));
1323
	memcpy(buf+nl, " ", 1);
1323
	memcpy(buf+nl, " ", 1);
1324
    }
1324
    }
1325
    /* don't add Calls if it adds no extra information */
1325
    /* don't add Calls if it adds no extra information */
1326
    /* However: do we want to include the call in the list if it is a
1326
    /* However: do we want to include the call in the list if it is a
1327
       primitive? */
1327
       primitive? */
1328
    if (ncalls == 1 && call != R_NilValue) {
1328
    if (ncalls == 1 && call != R_NilValue) {
1329
	SEXP fun = CAR(call);
1329
	SEXP fun = CAR(call);
1330
	const char *this = (TYPEOF(fun) == SYMSXP) ?
1330
	const char *this = (TYPEOF(fun) == SYMSXP) ?
1331
	    CHAR(PRINTNAME(fun)) : "<Anonymous>";
1331
	    CHAR(PRINTNAME(fun)) : "<Anonymous>";
1332
	if(streql(buf, this)) return "";
1332
	if(streql(buf, this)) return "";
1333
    }
1333
    }
1334
    return buf;
1334
    return buf;
1335
}
1335
}
1336
 
1336
 
1337
 
1337
 
1338
 
1338
 
1339
static SEXP mkHandlerEntry(SEXP klass, SEXP parentenv, SEXP handler, SEXP rho,
1339
static SEXP mkHandlerEntry(SEXP klass, SEXP parentenv, SEXP handler, SEXP rho,
1340
			   SEXP result, int calling)
1340
			   SEXP result, int calling)
1341
{
1341
{
1342
    SEXP entry = allocVector(VECSXP, 5);
1342
    SEXP entry = allocVector(VECSXP, 5);
1343
    SET_VECTOR_ELT(entry, 0, klass);
1343
    SET_VECTOR_ELT(entry, 0, klass);
1344
    SET_VECTOR_ELT(entry, 1, parentenv);
1344
    SET_VECTOR_ELT(entry, 1, parentenv);
1345
    SET_VECTOR_ELT(entry, 2, handler);
1345
    SET_VECTOR_ELT(entry, 2, handler);
1346
    SET_VECTOR_ELT(entry, 3, rho);
1346
    SET_VECTOR_ELT(entry, 3, rho);
1347
    SET_VECTOR_ELT(entry, 4, result);
1347
    SET_VECTOR_ELT(entry, 4, result);
1348
    SETLEVELS(entry, calling);
1348
    SETLEVELS(entry, calling);
1349
    return entry;
1349
    return entry;
1350
}
1350
}
1351
 
1351
 
1352
/**** rename these??*/
1352
/**** rename these??*/
1353
#define IS_CALLING_ENTRY(e) LEVELS(e)
1353
#define IS_CALLING_ENTRY(e) LEVELS(e)
1354
#define ENTRY_CLASS(e) VECTOR_ELT(e, 0)
1354
#define ENTRY_CLASS(e) VECTOR_ELT(e, 0)
1355
#define ENTRY_CALLING_ENVIR(e) VECTOR_ELT(e, 1)
1355
#define ENTRY_CALLING_ENVIR(e) VECTOR_ELT(e, 1)
1356
#define ENTRY_HANDLER(e) VECTOR_ELT(e, 2)
1356
#define ENTRY_HANDLER(e) VECTOR_ELT(e, 2)
1357
#define ENTRY_TARGET_ENVIR(e) VECTOR_ELT(e, 3)
1357
#define ENTRY_TARGET_ENVIR(e) VECTOR_ELT(e, 3)
1358
#define ENTRY_RETURN_RESULT(e) VECTOR_ELT(e, 4)
1358
#define ENTRY_RETURN_RESULT(e) VECTOR_ELT(e, 4)
1359
 
1359
 
1360
#define RESULT_SIZE 3
1360
#define RESULT_SIZE 3
1361
 
1361
 
1362
SEXP attribute_hidden do_addCondHands(SEXP call, SEXP op, SEXP args, SEXP rho)
1362
SEXP attribute_hidden do_addCondHands(SEXP call, SEXP op, SEXP args, SEXP rho)
1363
{
1363
{
1364
    SEXP classes, handlers, parentenv, target, oldstack, newstack, result;
1364
    SEXP classes, handlers, parentenv, target, oldstack, newstack, result;
1365
    int calling, i, n;
1365
    int calling, i, n;
1366
    PROTECT_INDEX osi;
1366
    PROTECT_INDEX osi;
1367
 
1367
 
1368
    checkArity(op, args);
1368
    checkArity(op, args);
1369
 
1369
 
1370
    classes = CAR(args); args = CDR(args);
1370
    classes = CAR(args); args = CDR(args);
1371
    handlers = CAR(args); args = CDR(args);
1371
    handlers = CAR(args); args = CDR(args);
1372
    parentenv = CAR(args); args = CDR(args);
1372
    parentenv = CAR(args); args = CDR(args);
1373
    target = CAR(args); args = CDR(args);
1373
    target = CAR(args); args = CDR(args);
1374
    calling = asLogical(CAR(args));
1374
    calling = asLogical(CAR(args));
1375
 
1375
 
1376
    if (classes == R_NilValue || handlers == R_NilValue)
1376
    if (classes == R_NilValue || handlers == R_NilValue)
1377
	return R_HandlerStack;
1377
	return R_HandlerStack;
1378
 
1378
 
1379
    if (TYPEOF(classes) != STRSXP || TYPEOF(handlers) != VECSXP ||
1379
    if (TYPEOF(classes) != STRSXP || TYPEOF(handlers) != VECSXP ||
1380
	LENGTH(classes) != LENGTH(handlers))
1380
	LENGTH(classes) != LENGTH(handlers))
1381
	error(_("bad handler data"));
1381
	error(_("bad handler data"));
1382
 
1382
 
1383
    n = LENGTH(handlers);
1383
    n = LENGTH(handlers);
1384
    oldstack = R_HandlerStack;
1384
    oldstack = R_HandlerStack;
1385
 
1385
 
1386
    PROTECT(result = allocVector(VECSXP, RESULT_SIZE));
1386
    PROTECT(result = allocVector(VECSXP, RESULT_SIZE));
1387
    PROTECT_WITH_INDEX(newstack = oldstack, &osi);
1387
    PROTECT_WITH_INDEX(newstack = oldstack, &osi);
1388
 
1388
 
1389
    for (i = n - 1; i >= 0; i--) {
1389
    for (i = n - 1; i >= 0; i--) {
1390
	SEXP klass = STRING_ELT(classes, i);
1390
	SEXP klass = STRING_ELT(classes, i);
1391
	SEXP handler = VECTOR_ELT(handlers, i);
1391
	SEXP handler = VECTOR_ELT(handlers, i);
1392
	SEXP entry = mkHandlerEntry(klass, parentenv, handler, target, result,
1392
	SEXP entry = mkHandlerEntry(klass, parentenv, handler, target, result,
1393
				    calling);
1393
				    calling);
1394
	REPROTECT(newstack = CONS(entry, newstack), osi);
1394
	REPROTECT(newstack = CONS(entry, newstack), osi);
1395
    }
1395
    }
1396
 
1396
 
1397
    R_HandlerStack = newstack;
1397
    R_HandlerStack = newstack;
1398
    UNPROTECT(2);
1398
    UNPROTECT(2);
1399
 
1399
 
1400
    return oldstack;
1400
    return oldstack;
1401
}
1401
}
1402
 
1402
 
1403
SEXP attribute_hidden do_resetCondHands(SEXP call, SEXP op, SEXP args, SEXP rho)
1403
SEXP attribute_hidden do_resetCondHands(SEXP call, SEXP op, SEXP args, SEXP rho)
1404
{
1404
{
1405
    checkArity(op, args);
1405
    checkArity(op, args);
1406
    R_HandlerStack = CAR(args);
1406
    R_HandlerStack = CAR(args);
1407
    return R_NilValue;
1407
    return R_NilValue;
1408
}
1408
}
1409
 
1409
 
1410
static SEXP findSimpleErrorHandler()
1410
static SEXP findSimpleErrorHandler()
1411
{
1411
{
1412
    SEXP list;
1412
    SEXP list;
1413
    for (list = R_HandlerStack; list != R_NilValue; list = CDR(list)) {
1413
    for (list = R_HandlerStack; list != R_NilValue; list = CDR(list)) {
1414
	SEXP entry = CAR(list);
1414
	SEXP entry = CAR(list);
1415
	if (! strcmp(CHAR(ENTRY_CLASS(entry)), "simpleError") ||
1415
	if (! strcmp(CHAR(ENTRY_CLASS(entry)), "simpleError") ||
1416
	    ! strcmp(CHAR(ENTRY_CLASS(entry)), "error") ||
1416
	    ! strcmp(CHAR(ENTRY_CLASS(entry)), "error") ||
1417
	    ! strcmp(CHAR(ENTRY_CLASS(entry)), "condition"))
1417
	    ! strcmp(CHAR(ENTRY_CLASS(entry)), "condition"))
1418
	    return list;
1418
	    return list;
1419
    }
1419
    }
1420
    return R_NilValue;
1420
    return R_NilValue;
1421
}
1421
}
1422
 
1422
 
1423
static void vsignalWarning(SEXP call, const char *format, va_list ap)
1423
static void vsignalWarning(SEXP call, const char *format, va_list ap)
1424
{
1424
{
1425
    char buf[BUFSIZE];
1425
    char buf[BUFSIZE];
1426
    SEXP hooksym, quotesym, hcall, qcall;
1426
    SEXP hooksym, quotesym, hcall, qcall;
1427
 
1427
 
1428
    hooksym = install(".signalSimpleWarning");
1428
    hooksym = install(".signalSimpleWarning");
1429
    quotesym = install("quote");
1429
    quotesym = install("quote");
1430
    if (SYMVALUE(hooksym) != R_UnboundValue &&
1430
    if (SYMVALUE(hooksym) != R_UnboundValue &&
1431
	SYMVALUE(quotesym) != R_UnboundValue) {
1431
	SYMVALUE(quotesym) != R_UnboundValue) {
1432
	PROTECT(qcall = LCONS(quotesym, LCONS(call, R_NilValue)));
1432
	PROTECT(qcall = LCONS(quotesym, LCONS(call, R_NilValue)));
1433
	PROTECT(hcall = LCONS(qcall, R_NilValue));
1433
	PROTECT(hcall = LCONS(qcall, R_NilValue));
1434
	Rvsnprintf(buf, BUFSIZE - 1, format, ap);
1434
	Rvsnprintf(buf, BUFSIZE - 1, format, ap);
1435
	hcall = LCONS(ScalarString(mkChar(buf)), hcall);
1435
	hcall = LCONS(ScalarString(mkChar(buf)), hcall);
1436
	PROTECT(hcall = LCONS(hooksym, hcall));
1436
	PROTECT(hcall = LCONS(hooksym, hcall));
1437
	eval(hcall, R_GlobalEnv);
1437
	eval(hcall, R_GlobalEnv);
1438
	UNPROTECT(3);
1438
	UNPROTECT(3);
1439
    }
1439
    }
1440
    else vwarningcall_dflt(call, format, ap);
1440
    else vwarningcall_dflt(call, format, ap);
1441
}
1441
}
1442
 
1442
 
1443
static void gotoExitingHandler(SEXP cond, SEXP call, SEXP entry)
1443
static void gotoExitingHandler(SEXP cond, SEXP call, SEXP entry)
1444
{
1444
{
1445
    SEXP rho = ENTRY_TARGET_ENVIR(entry);
1445
    SEXP rho = ENTRY_TARGET_ENVIR(entry);
1446
    SEXP result = ENTRY_RETURN_RESULT(entry);
1446
    SEXP result = ENTRY_RETURN_RESULT(entry);
1447
    SET_VECTOR_ELT(result, 0, cond);
1447
    SET_VECTOR_ELT(result, 0, cond);
1448
    SET_VECTOR_ELT(result, 1, call);
1448
    SET_VECTOR_ELT(result, 1, call);
1449
    SET_VECTOR_ELT(result, 2, ENTRY_HANDLER(entry));
1449
    SET_VECTOR_ELT(result, 2, ENTRY_HANDLER(entry));
1450
    findcontext(CTXT_FUNCTION, rho, result);
1450
    findcontext(CTXT_FUNCTION, rho, result);
1451
}
1451
}
1452
 
1452
 
1453
static void vsignalError(SEXP call, const char *format, va_list ap)
1453
static void vsignalError(SEXP call, const char *format, va_list ap)
1454
{
1454
{
1455
    char localbuf[BUFSIZE];
1455
    char localbuf[BUFSIZE];
1456
    SEXP list, oldstack;
1456
    SEXP list, oldstack;
1457
 
1457
 
1458
    oldstack = R_HandlerStack;
1458
    oldstack = R_HandlerStack;
1459
    Rvsnprintf(localbuf, BUFSIZE - 1, format, ap);
1459
    Rvsnprintf(localbuf, BUFSIZE - 1, format, ap);
1460
    while ((list = findSimpleErrorHandler()) != R_NilValue) {
1460
    while ((list = findSimpleErrorHandler()) != R_NilValue) {
1461
	char *buf = errbuf;
1461
	char *buf = errbuf;
1462
	SEXP entry = CAR(list);
1462
	SEXP entry = CAR(list);
1463
	R_HandlerStack = CDR(list);
1463
	R_HandlerStack = CDR(list);
1464
	strncpy(buf, localbuf, BUFSIZE - 1);
1464
	strncpy(buf, localbuf, BUFSIZE - 1);
1465
	/*	Rvsnprintf(buf, BUFSIZE - 1, format, ap);*/
1465
	/*	Rvsnprintf(buf, BUFSIZE - 1, format, ap);*/
1466
	buf[BUFSIZE - 1] = 0;
1466
	buf[BUFSIZE - 1] = 0;
1467
	if (IS_CALLING_ENTRY(entry)) {
1467
	if (IS_CALLING_ENTRY(entry)) {
1468
	    if (ENTRY_HANDLER(entry) == R_RestartToken)
1468
	    if (ENTRY_HANDLER(entry) == R_RestartToken)
1469
		return; /* go to default error handling; do not reset stack */
1469
		return; /* go to default error handling; do not reset stack */
1470
	    else {
1470
	    else {
1471
		SEXP hooksym, quotesym, hcall, qcall;
1471
		SEXP hooksym, quotesym, hcall, qcall;
1472
		/* protect oldstack here, not outside loop, so handler
1472
		/* protect oldstack here, not outside loop, so handler
1473
		   stack gets unwound in case error is protect stack
1473
		   stack gets unwound in case error is protect stack
1474
		   overflow */
1474
		   overflow */
1475
		PROTECT(oldstack);
1475
		PROTECT(oldstack);
1476
		hooksym = install(".handleSimpleError");
1476
		hooksym = install(".handleSimpleError");
1477
		quotesym = install("quote");
1477
		quotesym = install("quote");
1478
		PROTECT(qcall = LCONS(quotesym, LCONS(call, R_NilValue)));
1478
		PROTECT(qcall = LCONS(quotesym, LCONS(call, R_NilValue)));
1479
		PROTECT(hcall = LCONS(qcall, R_NilValue));
1479
		PROTECT(hcall = LCONS(qcall, R_NilValue));
1480
		hcall = LCONS(ScalarString(mkChar(buf)), hcall);
1480
		hcall = LCONS(ScalarString(mkChar(buf)), hcall);
1481
		hcall = LCONS(ENTRY_HANDLER(entry), hcall);
1481
		hcall = LCONS(ENTRY_HANDLER(entry), hcall);
1482
		PROTECT(hcall = LCONS(hooksym, hcall));
1482
		PROTECT(hcall = LCONS(hooksym, hcall));
1483
		eval(hcall, R_GlobalEnv);
1483
		eval(hcall, R_GlobalEnv);
1484
		UNPROTECT(4);
1484
		UNPROTECT(4);
1485
	    }
1485
	    }
1486
	}
1486
	}
1487
	else gotoExitingHandler(R_NilValue, call, entry);
1487
	else gotoExitingHandler(R_NilValue, call, entry);
1488
    }
1488
    }
1489
    R_HandlerStack = oldstack;
1489
    R_HandlerStack = oldstack;
1490
}
1490
}
1491
 
1491
 
1492
static SEXP findConditionHandler(SEXP cond)
1492
static SEXP findConditionHandler(SEXP cond)
1493
{
1493
{
1494
    int i;
1494
    int i;
1495
    SEXP list;
1495
    SEXP list;
1496
    SEXP classes = getAttrib(cond, R_ClassSymbol);
1496
    SEXP classes = getAttrib(cond, R_ClassSymbol);
1497
 
1497
 
1498
    if (TYPEOF(classes) != STRSXP)
1498
    if (TYPEOF(classes) != STRSXP)
1499
	return R_NilValue;
1499
	return R_NilValue;
1500
 
1500
 
1501
    /**** need some changes here to allow conditions to be S4 classes */
1501
    /**** need some changes here to allow conditions to be S4 classes */
1502
    for (list = R_HandlerStack; list != R_NilValue; list = CDR(list)) {
1502
    for (list = R_HandlerStack; list != R_NilValue; list = CDR(list)) {
1503
	SEXP entry = CAR(list);
1503
	SEXP entry = CAR(list);
1504
	for (i = 0; i < LENGTH(classes); i++)
1504
	for (i = 0; i < LENGTH(classes); i++)
1505
	    if (! strcmp(CHAR(ENTRY_CLASS(entry)),
1505
	    if (! strcmp(CHAR(ENTRY_CLASS(entry)),
1506
			 CHAR(STRING_ELT(classes, i))))
1506
			 CHAR(STRING_ELT(classes, i))))
1507
		return list;
1507
		return list;
1508
    }
1508
    }
1509
    return R_NilValue;
1509
    return R_NilValue;
1510
}
1510
}
1511
 
1511
 
1512
SEXP attribute_hidden do_signalCondition(SEXP call, SEXP op, SEXP args, SEXP rho)
1512
SEXP attribute_hidden do_signalCondition(SEXP call, SEXP op, SEXP args, SEXP rho)
1513
{
1513
{
1514
    SEXP list, cond, msg, ecall, oldstack;
1514
    SEXP list, cond, msg, ecall, oldstack;
1515
 
1515
 
1516
    checkArity(op, args);
1516
    checkArity(op, args);
1517
 
1517
 
1518
    cond = CAR(args);
1518
    cond = CAR(args);
1519
    msg = CADR(args);
1519
    msg = CADR(args);
1520
    ecall = CADDR(args);
1520
    ecall = CADDR(args);
1521
 
1521
 
1522
    PROTECT(oldstack = R_HandlerStack);
1522
    PROTECT(oldstack = R_HandlerStack);
1523
    while ((list = findConditionHandler(cond)) != R_NilValue) {
1523
    while ((list = findConditionHandler(cond)) != R_NilValue) {
1524
	SEXP entry = CAR(list);
1524
	SEXP entry = CAR(list);
1525
	R_HandlerStack = CDR(list);
1525
	R_HandlerStack = CDR(list);
1526
	if (IS_CALLING_ENTRY(entry)) {
1526
	if (IS_CALLING_ENTRY(entry)) {
1527
	    SEXP h = ENTRY_HANDLER(entry);
1527
	    SEXP h = ENTRY_HANDLER(entry);
1528
	    if (h == R_RestartToken) {
1528
	    if (h == R_RestartToken) {
1529
		const char *msgstr = NULL;
1529
		const char *msgstr = NULL;
1530
		if (TYPEOF(msg) == STRSXP && LENGTH(msg) > 0)
1530
		if (TYPEOF(msg) == STRSXP && LENGTH(msg) > 0)
1531
		    msgstr = translateChar(STRING_ELT(msg, 0));
1531
		    msgstr = translateChar(STRING_ELT(msg, 0));
1532
		else error(_("error message not a string"));
1532
		else error(_("error message not a string"));
1533
		errorcall_dflt(ecall, "%s", msgstr);
1533
		errorcall_dflt(ecall, "%s", msgstr);
1534
	    }
1534
	    }
1535
	    else {
1535
	    else {
1536
		SEXP hcall = LCONS(h, LCONS(cond, R_NilValue));
1536
		SEXP hcall = LCONS(h, LCONS(cond, R_NilValue));
1537
		PROTECT(hcall);
1537
		PROTECT(hcall);
1538
		eval(hcall, R_GlobalEnv);
1538
		eval(hcall, R_GlobalEnv);
1539
		UNPROTECT(1);
1539
		UNPROTECT(1);
1540
	    }
1540
	    }
1541
	}
1541
	}
1542
	else gotoExitingHandler(cond, ecall, entry);
1542
	else gotoExitingHandler(cond, ecall, entry);
1543
    }
1543
    }
1544
    R_HandlerStack = oldstack;
1544
    R_HandlerStack = oldstack;
1545
    UNPROTECT(1);
1545
    UNPROTECT(1);
1546
    return R_NilValue;
1546
    return R_NilValue;
1547
}
1547
}
1548
 
1548
 
1549
static SEXP findInterruptHandler()
1549
static SEXP findInterruptHandler()
1550
{
1550
{
1551
    SEXP list;
1551
    SEXP list;
1552
    for (list = R_HandlerStack; list != R_NilValue; list = CDR(list)) {
1552
    for (list = R_HandlerStack; list != R_NilValue; list = CDR(list)) {
1553
	SEXP entry = CAR(list);
1553
	SEXP entry = CAR(list);
1554
	if (! strcmp(CHAR(ENTRY_CLASS(entry)), "interrupt") ||
1554
	if (! strcmp(CHAR(ENTRY_CLASS(entry)), "interrupt") ||
1555
	    ! strcmp(CHAR(ENTRY_CLASS(entry)), "condition"))
1555
	    ! strcmp(CHAR(ENTRY_CLASS(entry)), "condition"))
1556
	    return list;
1556
	    return list;
1557
    }
1557
    }
1558
    return R_NilValue;
1558
    return R_NilValue;
1559
}
1559
}
1560
 
1560
 
1561
static SEXP getInterruptCondition()
1561
static SEXP getInterruptCondition()
1562
{
1562
{
1563
    /**** FIXME: should probably pre-allocate this */
1563
    /**** FIXME: should probably pre-allocate this */
1564
    SEXP cond, klass;
1564
    SEXP cond, klass;
1565
    PROTECT(cond = allocVector(VECSXP, 0));
1565
    PROTECT(cond = allocVector(VECSXP, 0));
1566
    PROTECT(klass = allocVector(STRSXP, 2));
1566
    PROTECT(klass = allocVector(STRSXP, 2));
1567
    SET_STRING_ELT(klass, 0, mkChar("interrupt"));
1567
    SET_STRING_ELT(klass, 0, mkChar("interrupt"));
1568
    SET_STRING_ELT(klass, 1, mkChar("condition"));
1568
    SET_STRING_ELT(klass, 1, mkChar("condition"));
1569
    classgets(cond, klass);
1569
    classgets(cond, klass);
1570
    UNPROTECT(2);
1570
    UNPROTECT(2);
1571
    return cond;
1571
    return cond;
1572
}
1572
}
1573
 
1573
 
1574
static void signalInterrupt(void)
1574
static void signalInterrupt(void)
1575
{
1575
{
1576
    SEXP list, cond, oldstack;
1576
    SEXP list, cond, oldstack;
1577
 
1577
 
1578
    PROTECT(oldstack = R_HandlerStack);
1578
    PROTECT(oldstack = R_HandlerStack);
1579
    while ((list = findInterruptHandler()) != R_NilValue) {
1579
    while ((list = findInterruptHandler()) != R_NilValue) {
1580
	SEXP entry = CAR(list);
1580
	SEXP entry = CAR(list);
1581
	R_HandlerStack = CDR(list);
1581
	R_HandlerStack = CDR(list);
1582
	PROTECT(cond = getInterruptCondition());
1582
	PROTECT(cond = getInterruptCondition());
1583
	if (IS_CALLING_ENTRY(entry)) {
1583
	if (IS_CALLING_ENTRY(entry)) {
1584
	    SEXP h = ENTRY_HANDLER(entry);
1584
	    SEXP h = ENTRY_HANDLER(entry);
1585
	    SEXP hcall = LCONS(h, LCONS(cond, R_NilValue));
1585
	    SEXP hcall = LCONS(h, LCONS(cond, R_NilValue));
1586
	    PROTECT(hcall);
1586
	    PROTECT(hcall);
1587
	    eval(hcall, R_GlobalEnv);
1587
	    eval(hcall, R_GlobalEnv);
1588
	    UNPROTECT(1);
1588
	    UNPROTECT(1);
1589
	}
1589
	}
1590
	else gotoExitingHandler(cond, R_NilValue, entry);
1590
	else gotoExitingHandler(cond, R_NilValue, entry);
1591
	UNPROTECT(1);
1591
	UNPROTECT(1);
1592
    }
1592
    }
1593
    R_HandlerStack = oldstack;
1593
    R_HandlerStack = oldstack;
1594
    UNPROTECT(1);
1594
    UNPROTECT(1);
1595
}
1595
}
1596
 
1596
 
1597
void attribute_hidden
1597
void attribute_hidden
1598
R_InsertRestartHandlers(RCNTXT *cptr, Rboolean browser)
1598
R_InsertRestartHandlers(RCNTXT *cptr, Rboolean browser)
1599
{
1599
{
1600
    SEXP klass, rho, entry, name;
1600
    SEXP klass, rho, entry, name;
1601
 
1601
 
1602
    if ((cptr->handlerstack != R_HandlerStack ||
1602
    if ((cptr->handlerstack != R_HandlerStack ||
1603
	 cptr->handlerstack != R_HandlerStack)) {
1603
	 cptr->handlerstack != R_HandlerStack)) {
1604
	if (IS_RESTART_BIT_SET(cptr->callflag))
1604
	if (IS_RESTART_BIT_SET(cptr->callflag))
1605
	    return;
1605
	    return;
1606
	else
1606
	else
1607
	    error(_("handler or restart stack mismatch in old restart"));
1607
	    error(_("handler or restart stack mismatch in old restart"));
1608
    }
1608
    }
1609
 
1609
 
1610
    /**** need more here to keep recursive errors in browser? */
1610
    /**** need more here to keep recursive errors in browser? */
1611
    rho = cptr->cloenv;
1611
    rho = cptr->cloenv;
1612
    PROTECT(klass = mkChar("error"));
1612
    PROTECT(klass = mkChar("error"));
1613
    entry = mkHandlerEntry(klass, rho, R_RestartToken, rho, R_NilValue, TRUE);
1613
    entry = mkHandlerEntry(klass, rho, R_RestartToken, rho, R_NilValue, TRUE);
1614
    R_HandlerStack = CONS(entry, R_HandlerStack);
1614
    R_HandlerStack = CONS(entry, R_HandlerStack);
1615
    UNPROTECT(1);
1615
    UNPROTECT(1);
1616
    PROTECT(name = ScalarString(mkChar(browser ? "browser" : "tryRestart")));
1616
    PROTECT(name = ScalarString(mkChar(browser ? "browser" : "tryRestart")));
1617
    PROTECT(entry = allocVector(VECSXP, 2));
1617
    PROTECT(entry = allocVector(VECSXP, 2));
1618
    PROTECT(SET_VECTOR_ELT(entry, 0, name));
1618
    PROTECT(SET_VECTOR_ELT(entry, 0, name));
1619
    SET_VECTOR_ELT(entry, 1, R_MakeExternalPtr(cptr, R_NilValue, R_NilValue));
1619
    SET_VECTOR_ELT(entry, 1, R_MakeExternalPtr(cptr, R_NilValue, R_NilValue));
1620
    setAttrib(entry, R_ClassSymbol, ScalarString(mkChar("restart")));
1620
    setAttrib(entry, R_ClassSymbol, ScalarString(mkChar("restart")));
1621
    R_RestartStack = CONS(entry, R_RestartStack);
1621
    R_RestartStack = CONS(entry, R_RestartStack);
1622
    UNPROTECT(3);
1622
    UNPROTECT(3);
1623
}
1623
}
1624
 
1624
 
1625
SEXP attribute_hidden do_dfltWarn(SEXP call, SEXP op, SEXP args, SEXP rho)
1625
SEXP attribute_hidden do_dfltWarn(SEXP call, SEXP op, SEXP args, SEXP rho)
1626
{
1626
{
1627
    const char *msg;
1627
    const char *msg;
1628
    SEXP ecall;
1628
    SEXP ecall;
1629
 
1629
 
1630
    checkArity(op, args);
1630
    checkArity(op, args);
1631
 
1631
 
1632
    if (TYPEOF(CAR(args)) != STRSXP || LENGTH(CAR(args)) != 1)
1632
    if (TYPEOF(CAR(args)) != STRSXP || LENGTH(CAR(args)) != 1)
1633
	error(_("bad error message"));
1633
	error(_("bad error message"));
1634
    msg = translateChar(STRING_ELT(CAR(args), 0));
1634
    msg = translateChar(STRING_ELT(CAR(args), 0));
1635
    ecall = CADR(args);
1635
    ecall = CADR(args);
1636
 
1636
 
1637
    warningcall_dflt(ecall, "%s", msg);
1637
    warningcall_dflt(ecall, "%s", msg);
1638
    return R_NilValue;
1638
    return R_NilValue;
1639
}
1639
}
1640
 
1640
 
1641
SEXP attribute_hidden do_dfltStop(SEXP call, SEXP op, SEXP args, SEXP rho)
1641
SEXP attribute_hidden do_dfltStop(SEXP call, SEXP op, SEXP args, SEXP rho)
1642
{
1642
{
1643
    const char *msg;
1643
    const char *msg;
1644
    SEXP ecall;
1644
    SEXP ecall;
1645
 
1645
 
1646
    checkArity(op, args);
1646
    checkArity(op, args);
1647
 
1647
 
1648
    if (TYPEOF(CAR(args)) != STRSXP || LENGTH(CAR(args)) != 1)
1648
    if (TYPEOF(CAR(args)) != STRSXP || LENGTH(CAR(args)) != 1)
1649
	error(_("bad error message"));
1649
	error(_("bad error message"));
1650
    msg = translateChar(STRING_ELT(CAR(args), 0));
1650
    msg = translateChar(STRING_ELT(CAR(args), 0));
1651
    ecall = CADR(args);
1651
    ecall = CADR(args);
1652
 
1652
 
1653
    errorcall_dflt(ecall, "%s", msg);
1653
    errorcall_dflt(ecall, "%s", msg);
1654
    return R_NilValue; /* not reached */
1654
    return R_NilValue; /* not reached */
1655
}
1655
}
1656
 
1656
 
1657
 
1657
 
1658
/*
1658
/*
1659
 * Restart Handling
1659
 * Restart Handling
1660
 */
1660
 */
1661
 
1661
 
1662
SEXP attribute_hidden do_getRestart(SEXP call, SEXP op, SEXP args, SEXP rho)
1662
SEXP attribute_hidden do_getRestart(SEXP call, SEXP op, SEXP args, SEXP rho)
1663
{
1663
{
1664
    int i;
1664
    int i;
1665
    SEXP list;
1665
    SEXP list;
1666
    checkArity(op, args);
1666
    checkArity(op, args);
1667
    i = asInteger(CAR(args));
1667
    i = asInteger(CAR(args));
1668
    for (list = R_RestartStack;
1668
    for (list = R_RestartStack;
1669
	 list != R_NilValue && i > 1;
1669
	 list != R_NilValue && i > 1;
1670
	 list = CDR(list), i--);
1670
	 list = CDR(list), i--);
1671
    if (list != R_NilValue)
1671
    if (list != R_NilValue)
1672
	return CAR(list);
1672
	return CAR(list);
1673
    else if (i == 1) {
1673
    else if (i == 1) {
1674
	/**** need to pre-allocate */
1674
	/**** need to pre-allocate */
1675
	SEXP name, entry;
1675
	SEXP name, entry;
1676
	PROTECT(name = ScalarString(mkChar("abort")));
1676
	PROTECT(name = ScalarString(mkChar("abort")));
1677
	entry = allocVector(VECSXP, 2);
1677
	entry = allocVector(VECSXP, 2);
1678
	SET_VECTOR_ELT(entry, 0, name);
1678
	SET_VECTOR_ELT(entry, 0, name);
1679
	SET_VECTOR_ELT(entry, 1, R_NilValue);
1679
	SET_VECTOR_ELT(entry, 1, R_NilValue);
1680
	setAttrib(entry, R_ClassSymbol, ScalarString(mkChar("restart")));
1680
	setAttrib(entry, R_ClassSymbol, ScalarString(mkChar("restart")));
1681
	UNPROTECT(1);
1681
	UNPROTECT(1);
1682
	return entry;
1682
	return entry;
1683
    }
1683
    }
1684
    else return R_NilValue;
1684
    else return R_NilValue;
1685
}
1685
}
1686
 
1686
 
1687
/* very minimal error checking --just enough to avoid a segfault */
1687
/* very minimal error checking --just enough to avoid a segfault */
1688
#define CHECK_RESTART(r) do { \
1688
#define CHECK_RESTART(r) do { \
1689
    SEXP __r__ = (r); \
1689
    SEXP __r__ = (r); \
1690
    if (TYPEOF(__r__) != VECSXP || LENGTH(__r__) < 2) \
1690
    if (TYPEOF(__r__) != VECSXP || LENGTH(__r__) < 2) \
1691
	error(_("bad restart")); \
1691
	error(_("bad restart")); \
1692
} while (0)
1692
} while (0)
1693
 
1693
 
1694
SEXP attribute_hidden do_addRestart(SEXP call, SEXP op, SEXP args, SEXP rho)
1694
SEXP attribute_hidden do_addRestart(SEXP call, SEXP op, SEXP args, SEXP rho)
1695
{
1695
{
1696
    checkArity(op, args);
1696
    checkArity(op, args);
1697
    CHECK_RESTART(CAR(args));
1697
    CHECK_RESTART(CAR(args));
1698
    R_RestartStack = CONS(CAR(args), R_RestartStack);
1698
    R_RestartStack = CONS(CAR(args), R_RestartStack);
1699
    return R_NilValue;
1699
    return R_NilValue;
1700
}
1700
}
1701
 
1701
 
1702
#define RESTART_EXIT(r) VECTOR_ELT(r, 1)
1702
#define RESTART_EXIT(r) VECTOR_ELT(r, 1)
1703
 
1703
 
1704
static void invokeRestart(SEXP r, SEXP arglist)
1704
static void invokeRestart(SEXP r, SEXP arglist)
1705
{
1705
{
1706
    SEXP exit = RESTART_EXIT(r);
1706
    SEXP exit = RESTART_EXIT(r);
1707
 
1707
 
1708
    if (exit == R_NilValue) {
1708
    if (exit == R_NilValue) {
1709
	R_RestartStack = R_NilValue;
1709
	R_RestartStack = R_NilValue;
1710
	jump_to_toplevel();
1710
	jump_to_toplevel();
1711
    }
1711
    }
1712
    else {
1712
    else {
1713
	for (; R_RestartStack != R_NilValue;
1713
	for (; R_RestartStack != R_NilValue;
1714
	     R_RestartStack = CDR(R_RestartStack))
1714
	     R_RestartStack = CDR(R_RestartStack))
1715
	    if (exit == RESTART_EXIT(CAR(R_RestartStack))) {
1715
	    if (exit == RESTART_EXIT(CAR(R_RestartStack))) {
1716
		R_RestartStack = CDR(R_RestartStack);
1716
		R_RestartStack = CDR(R_RestartStack);
1717
		if (TYPEOF(exit) == EXTPTRSXP) {
1717
		if (TYPEOF(exit) == EXTPTRSXP) {
1718
		    RCNTXT *c = (RCNTXT *) R_ExternalPtrAddr(exit);
1718
		    RCNTXT *c = (RCNTXT *) R_ExternalPtrAddr(exit);
1719
		    R_JumpToContext(c, CTXT_RESTART, R_RestartToken);
1719
		    R_JumpToContext(c, CTXT_RESTART, R_RestartToken);
1720
		}
1720
		}
1721
		else findcontext(CTXT_FUNCTION, exit, arglist);
1721
		else findcontext(CTXT_FUNCTION, exit, arglist);
1722
	    }
1722
	    }
1723
	error(_("restart not on stack"));
1723
	error(_("restart not on stack"));
1724
    }
1724
    }
1725
}
1725
}
1726
 
1726
 
1727
SEXP attribute_hidden do_invokeRestart(SEXP call, SEXP op, SEXP args, SEXP rho)
1727
SEXP attribute_hidden do_invokeRestart(SEXP call, SEXP op, SEXP args, SEXP rho)
1728
{
1728
{
1729
    checkArity(op, args);
1729
    checkArity(op, args);
1730
    CHECK_RESTART(CAR(args));
1730
    CHECK_RESTART(CAR(args));
1731
    invokeRestart(CAR(args), CADR(args));
1731
    invokeRestart(CAR(args), CADR(args));
1732
    return R_NilValue; /* not reached */
1732
    return R_NilValue; /* not reached */
1733
}
1733
}
1734
 
1734
 
1735
SEXP attribute_hidden do_addTryHandlers(SEXP call, SEXP op, SEXP args, SEXP rho)
1735
SEXP attribute_hidden do_addTryHandlers(SEXP call, SEXP op, SEXP args, SEXP rho)
1736
{
1736
{
1737
    checkArity(op, args);
1737
    checkArity(op, args);
1738
    if (R_GlobalContext == R_ToplevelContext ||
1738
    if (R_GlobalContext == R_ToplevelContext ||
1739
	! R_GlobalContext->callflag & CTXT_FUNCTION)
1739
	! R_GlobalContext->callflag & CTXT_FUNCTION)
1740
	errorcall(call, _("not in a try context"));
1740
	errorcall(call, _("not in a try context"));
1741
    SET_RESTART_BIT_ON(R_GlobalContext->callflag);
1741
    SET_RESTART_BIT_ON(R_GlobalContext->callflag);
1742
    R_InsertRestartHandlers(R_GlobalContext, FALSE);
1742
    R_InsertRestartHandlers(R_GlobalContext, FALSE);
1743
    return R_NilValue;
1743
    return R_NilValue;
1744
}
1744
}
1745
 
1745
 
1746
SEXP attribute_hidden do_seterrmessage(SEXP call, SEXP op, SEXP args, SEXP env)
1746
SEXP attribute_hidden do_seterrmessage(SEXP call, SEXP op, SEXP args, SEXP env)
1747
{
1747
{
1748
    SEXP msg;
1748
    SEXP msg;
1749
 
1749
 
1750
    checkArity(op, args);
1750
    checkArity(op, args);
1751
    msg = CAR(args);
1751
    msg = CAR(args);
1752
    if(!isString(msg) || LENGTH(msg) != 1)
1752
    if(!isString(msg) || LENGTH(msg) != 1)
1753
	error(_("error message must be a character string"));
1753
	error(_("error message must be a character string"));
1754
    R_SetErrmessage(CHAR(STRING_ELT(msg, 0)));
1754
    R_SetErrmessage(CHAR(STRING_ELT(msg, 0)));
1755
    return R_NilValue;
1755
    return R_NilValue;
1756
}
1756
}
1757
 
1757
 
1758
SEXP attribute_hidden
1758
SEXP attribute_hidden
1759
do_printDeferredWarnings(SEXP call, SEXP op, SEXP args, SEXP env)
1759
do_printDeferredWarnings(SEXP call, SEXP op, SEXP args, SEXP env)
1760
{
1760
{
1761
    checkArity(op, args);
1761
    checkArity(op, args);
1762
    R_PrintDeferredWarnings();
1762
    R_PrintDeferredWarnings();
1763
    return R_NilValue;
1763
    return R_NilValue;
1764
}
1764
}