/* Provide a call-back mechanism for handling error output. Copyright (C) 1993 Free Software Foundation, Inc. Contributed by Jason Merrill (jason@cygnus.com) This file is part of GNU CC. GNU CC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU CC; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "config.h" #include "tree.h" #include /* cp_printer is the type of a function which converts an argument into a string for digestion by printf. The cp_printer function should deal with all memory management; the functions in this file will not free the char*s returned. See error.c for an example use of this code. */ typedef char* cp_printer PROTO((HOST_WIDE_INT, int)); extern cp_printer * cp_printers[256]; typedef void errorfn (); /* deliberately vague */ extern char* cp_file_of PROTO((tree)); extern int cp_line_of PROTO((tree)); #define STRDUP(f) (ap = (char *) alloca (strlen (f) +1), strcpy (ap, (f)), ap) #define NARGS 3 #define arglist a1, a2, a3 #define arglist_dcl HOST_WIDE_INT a1, a2, a3; #define ARGSINIT args[0] = a1; args[1] = a2; args[2] = a3; #define ARGSLIST args[0], args[1], args[2] static void cp_thing (errfn, atarg1, format, arglist) errorfn *errfn; int atarg1; char *format; arglist_dcl { char *fmt; char *f; char *ap; int arg; HOST_WIDE_INT atarg = atarg1 ? a1 : 0; HOST_WIDE_INT args[NARGS]; ARGSINIT fmt = STRDUP(format); for (f = fmt, arg = 0; *f; ++f) { cp_printer * function; int alternate; int maybe_here; /* ignore text */ if (*f != '%') continue; ++f; alternate = 0; maybe_here = 0; /* ignore most flags */ while (*f == ' ' || *f == '-' || *f == '+' || *f == '#') { if (*f == '+') maybe_here = 1; else if (*f == '#') alternate = 1; ++f; } /* ignore field width */ if (*f == '*') { ++f; ++arg; } else while (isdigit (*f)) ++f; /* ignore precision */ if (*f == '.') { ++f; if (*f == '*') { ++f; ++arg; } else while (isdigit (*f)) ++f; } /* ignore "long" */ if (*f == 'l') ++f; function = cp_printers[(int)*f]; if (function) { char *p; if (arg >= NARGS) abort (); if (maybe_here && atarg1) atarg = args[arg]; /* Must use a temporary to avoid calling *function twice */ p = (*function) (args[arg], alternate); args[arg] = (HOST_WIDE_INT) STRDUP(p); *f = 's'; } ++arg; /* Assume valid format string */ } if (atarg) { char *file = cp_file_of ((tree) atarg); int line = cp_line_of ((tree) atarg); (*errfn) (file, line, fmt, ARGSLIST); } else (*errfn) (fmt, ARGSLIST); } void cp_error (format, arglist) char *format; arglist_dcl { extern errorfn error; cp_thing (error, 0, format, arglist); } void cp_warning (format, arglist) char *format; arglist_dcl { extern errorfn warning; cp_thing (warning, 0, format, arglist); } void cp_pedwarn (format, arglist) char *format; arglist_dcl { extern errorfn pedwarn; cp_thing (pedwarn, 0, format, arglist); } void cp_compiler_error (format, arglist) char *format; arglist_dcl { extern errorfn compiler_error; cp_thing (compiler_error, 0, format, arglist); } void cp_sprintf (format, arglist) char *format; arglist_dcl { extern errorfn sprintf; cp_thing (sprintf, 0, format, arglist); } void cp_error_at (format, arglist) char *format; arglist_dcl { extern errorfn error_with_file_and_line; cp_thing (error_with_file_and_line, 1, format, arglist); } void cp_warning_at (format, arglist) char *format; arglist_dcl { extern errorfn warning_with_file_and_line; cp_thing (warning_with_file_and_line, 1, format, arglist); } void cp_pedwarn_at (format, arglist) char *format; arglist_dcl { extern errorfn pedwarn_with_file_and_line; cp_thing (pedwarn_with_file_and_line, 1, format, arglist); }