1/* Provide a call-back mechanism for handling error output.
2   Copyright (C) 1993, 94-98, 1999 Free Software Foundation, Inc.
3   Contributed by Jason Merrill (jason@cygnus.com)
4
5   This file is part of GNU CC.
6
7GNU CC is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2, or (at your option)
10any later version.
11
12GNU CC is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU CC; see the file COPYING.  If not, write to
19the Free Software Foundation, 59 Temple Place - Suite 330,
20Boston, MA 02111-1307, USA.  */
21
22#include "config.h"
23#include "system.h"
24#include "tree.h"
25#include "cp-tree.h"
26#include "toplev.h"
27
28/* cp_printer is the type of a function which converts an argument into
29   a string for digestion by printf.  The cp_printer function should deal
30   with all memory management; the functions in this file will not free
31   the char*s returned.  See error.c for an example use of this code.  */
32
33typedef char* cp_printer PROTO((tree, int));
34extern cp_printer * cp_printers[256];
35
36/* Whether or not we should try to be quiet for errors and warnings; this is
37   used to avoid being too talkative about problems with tentative choices
38   when we're computing the conversion costs for a method call.  */
39int cp_silent = 0;
40
41typedef void errorfn ();	/* deliberately vague */
42
43static void cp_thing PROTO ((errorfn *, int, const char *, va_list));
44
45#define STRDUP(f) (ap = (char *) alloca (strlen (f) +1), strcpy (ap, (f)), ap)
46
47/* This function supports only `%s', `%d', `%%', and the C++ print
48   codes.  */
49
50static void
51cp_thing (errfn, atarg1, format, ap)
52     errorfn *errfn;
53     int atarg1;
54     const char *format;
55     va_list ap;
56{
57  static char *buf;
58  static long buflen;
59  int nargs = 0;
60  long len;
61  long offset;
62  const char *f;
63  tree atarg = 0;
64
65  len = strlen (format) + 1;
66  if (len > buflen)
67    {
68      buflen = len;
69      buf = xrealloc (buf, buflen);
70    }
71  offset = 0;
72
73  for (f = format; *f; ++f)
74    {
75      cp_printer * function;
76      int alternate;
77      int maybe_here;
78
79      /* ignore text */
80      if (*f != '%')
81	{
82	  buf[offset++] = *f;
83	  continue;
84	}
85
86      ++f;
87
88      alternate = 0;
89      maybe_here = 0;
90
91      /* Check for '+' and '#' (in that order). */
92      if (*f == '+')
93	{
94	  maybe_here = 1;
95	  ++f;
96	}
97      if (*f == '#')
98	{
99	  alternate = 1;
100	  ++f;
101	}
102
103      /* no field width or precision */
104
105      function = cp_printers[(int)*f];
106
107      if (function || *f == 's')
108	{
109	  char *p;
110	  int plen;
111
112	  if (*f == 's')
113	    {
114	      p = va_arg (ap, char *);
115	      nargs++;
116	    }
117	  else
118	    {
119	      tree t = va_arg (ap, tree);
120	      nargs++;
121
122	      /* This indicates that ATARG comes from a different
123		 location than normal.  */
124	      if (maybe_here && atarg1)
125		atarg = t;
126
127	      /* If atarg1 is set and this is the first argument, then
128		 set ATARG appropriately.  */
129	      if (atarg1 && nargs == 1)
130		atarg = t;
131
132	      p = (*function) (t, alternate);
133	    }
134
135	  plen = strlen (p);
136	  len += plen;
137	  if (len > buflen)
138	    {
139	      buflen = len;
140	      buf = xrealloc (buf, len);
141	    }
142	  strcpy (buf + offset, p);
143	  offset += plen;
144	}
145      else if (*f == '%')
146	{
147	  /* A `%%' has occurred in the input string. Replace it with
148	     a `%' in the formatted message buf. */
149
150	  if (++len > buflen)
151	    {
152	      buflen = len;
153	      buf = xrealloc (buf, len);
154	    }
155	  buf[offset++] = '%';
156	}
157      else
158	{
159	  if (*f != 'd')
160	    abort ();
161	  len += HOST_BITS_PER_INT / 2;
162	  if (len > buflen)
163	    {
164	      buflen = len;
165	      buf = xrealloc (buf, len);
166	    }
167	  sprintf (buf + offset, "%d", va_arg (ap, int));
168	  nargs++;
169	  offset += strlen (buf + offset);
170	  /* With an ANSI C library one could write
171	     out += sprintf (...); */
172	}
173    }
174  buf[offset] = '\0';
175
176  /* If ATARG1 is set, but we haven't extracted any arguments, then
177     extract one tree argument for ATARG.  */
178  if (nargs == 0 && atarg1)
179    atarg = va_arg (ap, tree);
180
181  if (atarg)
182    {
183      char *file = cp_file_of (atarg);
184      int   line = cp_line_of (atarg);
185      (*errfn) (file, line, "%s", buf);
186    }
187  else
188    (*errfn) ("%s", buf);
189
190}
191
192void
193cp_error VPROTO((const char *format, ...))
194{
195#ifndef ANSI_PROTOTYPES
196  char *format;
197#endif
198  va_list ap;
199
200  VA_START (ap, format);
201
202#ifndef ANSI_PROTOTYPES
203  format = va_arg (ap, char *);
204#endif
205
206  if (! cp_silent)
207    cp_thing ((errorfn *) error, 0, format, ap);
208  va_end (ap);
209}
210
211void
212cp_warning VPROTO((const char *format, ...))
213{
214#ifndef ANSI_PROTOTYPES
215  char *format;
216#endif
217  va_list ap;
218
219  VA_START (ap, format);
220
221#ifndef ANSI_PROTOTYPES
222  format = va_arg (ap, char *);
223#endif
224
225  if (! cp_silent)
226    cp_thing ((errorfn *) warning, 0, format, ap);
227  va_end (ap);
228}
229
230void
231cp_pedwarn VPROTO((const char *format, ...))
232{
233#ifndef ANSI_PROTOTYPES
234  char *format;
235#endif
236  va_list ap;
237
238  VA_START (ap, format);
239
240#ifndef ANSI_PROTOTYPES
241  format = va_arg (ap, char *);
242#endif
243
244  if (! cp_silent)
245    cp_thing ((errorfn *) pedwarn, 0, format, ap);
246  va_end (ap);
247}
248
249void
250cp_compiler_error VPROTO((const char *format, ...))
251{
252#ifndef ANSI_PROTOTYPES
253  char *format;
254#endif
255  va_list ap;
256
257  VA_START (ap, format);
258
259#ifndef ANSI_PROTOTYPES
260  format = va_arg (ap, char *);
261#endif
262
263  if (! cp_silent)
264    cp_thing ((errorfn *) compiler_error, 0, format, ap);
265  va_end (ap);
266}
267
268void
269cp_deprecated (msg)
270  const char *msg;
271{
272  extern int warn_deprecated;
273  if (!warn_deprecated)
274    return;
275  cp_warning ("%s is deprecated.", msg);
276  cp_warning ("Please see the documentation for details.");
277}
278
279void
280cp_sprintf VPROTO((const char *format, ...))
281{
282#ifndef ANSI_PROTOTYPES
283  char *format;
284#endif
285  va_list ap;
286
287  VA_START (ap, format);
288
289#ifndef ANSI_PROTOTYPES
290  format = va_arg (ap, char *);
291#endif
292
293  cp_thing ((errorfn *) sprintf, 0, format, ap);
294  va_end (ap);
295}
296
297void
298cp_error_at VPROTO((const char *format, ...))
299{
300#ifndef ANSI_PROTOTYPES
301  char *format;
302#endif
303  va_list ap;
304
305  VA_START (ap, format);
306
307#ifndef ANSI_PROTOTYPES
308  format = va_arg (ap, char *);
309#endif
310
311  if (! cp_silent)
312    cp_thing ((errorfn *) error_with_file_and_line, 1, format, ap);
313  va_end (ap);
314}
315
316void
317cp_warning_at VPROTO((const char *format, ...))
318{
319#ifndef ANSI_PROTOTYPES
320  char *format;
321#endif
322  va_list ap;
323
324  VA_START (ap, format);
325
326#ifndef ANSI_PROTOTYPES
327  format = va_arg (ap, char *);
328#endif
329
330  if (! cp_silent)
331    cp_thing ((errorfn *) warning_with_file_and_line, 1, format, ap);
332  va_end (ap);
333}
334
335void
336cp_pedwarn_at VPROTO((const char *format, ...))
337{
338#ifndef ANSI_PROTOTYPES
339  char *format;
340#endif
341  va_list ap;
342
343  VA_START (ap, format);
344
345#ifndef ANSI_PROTOTYPES
346  format = va_arg (ap, char *);
347#endif
348
349  if (! cp_silent)
350    cp_thing ((errorfn *) pedwarn_with_file_and_line, 1, format, ap);
351  va_end (ap);
352}
353