Commit | Line | Data |
---|---|---|
970ed795 EL |
1 | /////////////////////////////////////////////////////////////////////////////// |
2 | // Copyright (c) 2000-2014 Ericsson Telecom AB | |
3 | // All rights reserved. This program and the accompanying materials | |
4 | // are made available under the terms of the Eclipse Public License v1.0 | |
5 | // which accompanies this distribution, and is available at | |
6 | // http://www.eclipse.org/legal/epl-v10.html | |
7 | /////////////////////////////////////////////////////////////////////////////// | |
8 | #include "error.h" | |
9 | #include "CompilerError.hh" | |
10 | #include "../common/memory.h" | |
11 | #include "../common/path.h" | |
12 | #include "main.hh" | |
13 | #include "Setting.hh" | |
14 | ||
15 | #include <stdio.h> | |
16 | #include <stdlib.h> | |
17 | #include <stdarg.h> | |
18 | #include <errno.h> | |
19 | #ifndef MINGW | |
20 | # include <sys/wait.h> | |
21 | #endif | |
22 | ||
23 | unsigned verb_level=0x0007; /* default value */ | |
24 | ||
25 | const char *argv0; /* the programname :) */ | |
26 | ||
27 | void fatal_error(const char *filename, int lineno, const char *fmt, ...) | |
28 | { | |
29 | va_list parameters; | |
30 | #ifdef FATAL_DEBUG | |
31 | va_start(parameters, fmt); | |
32 | Common::Location loc(filename, lineno); | |
33 | Common::Error_Context::report_error(&loc, fmt, parameters); | |
34 | va_end(parameters); | |
35 | #else | |
36 | fprintf(stderr, "FATAL ERROR: %s: In line %d of %s: ", | |
37 | argv0, lineno, filename); | |
38 | va_start(parameters, fmt); | |
39 | vfprintf(stderr, fmt, parameters); | |
40 | va_end(parameters); | |
41 | putc('\n', stderr); | |
42 | #endif | |
43 | fflush(stderr); | |
44 | abort(); | |
45 | } | |
46 | ||
47 | void ERROR(const char *fmt, ...) | |
48 | { | |
49 | fprintf(stderr, "%s: error: ", argv0); | |
50 | va_list parameters; | |
51 | va_start(parameters, fmt); | |
52 | vfprintf(stderr, fmt, parameters); | |
53 | va_end(parameters); | |
54 | putc('\n', stderr); | |
55 | fflush(stderr); | |
56 | Common::Error_Context::increment_error_count(); | |
57 | } | |
58 | ||
59 | void WARNING(const char *fmt, ...) | |
60 | { | |
61 | if(!(verb_level & 2)) return; | |
62 | fprintf(stderr, "%s: warning: ", argv0); | |
63 | va_list parameters; | |
64 | va_start(parameters, fmt); | |
65 | vfprintf(stderr, fmt, parameters); | |
66 | va_end(parameters); | |
67 | putc('\n', stderr); | |
68 | fflush(stderr); | |
69 | Common::Error_Context::increment_warning_count(); | |
70 | } | |
71 | ||
72 | void NOTSUPP(const char *fmt, ...) | |
73 | { | |
74 | if(!(verb_level & 1)) return; | |
75 | fprintf(stderr, "%s: warning: not supported: ", argv0); | |
76 | va_list parameters; | |
77 | va_start(parameters, fmt); | |
78 | vfprintf(stderr, fmt, parameters); | |
79 | va_end(parameters); | |
80 | putc('\n', stderr); | |
81 | fflush(stderr); | |
82 | Common::Error_Context::increment_warning_count(); | |
83 | } | |
84 | ||
85 | void NOTIFY(const char *fmt, ...) | |
86 | { | |
87 | if(!(verb_level & 4)) return; | |
88 | fprintf(stderr, "Notify: "); | |
89 | va_list parameters; | |
90 | va_start(parameters, fmt); | |
91 | vfprintf(stderr, fmt, parameters); | |
92 | va_end(parameters); | |
93 | putc('\n', stderr); | |
94 | fflush(stderr); | |
95 | } | |
96 | ||
97 | void DEBUG(unsigned level, const char *fmt, ...) | |
98 | { | |
99 | if((level>7?7:level)>((verb_level>>3)&0x07)) return; | |
100 | fprintf(stderr, "%*sDebug: ", level, ""); | |
101 | va_list parameters; | |
102 | va_start(parameters, fmt); | |
103 | vfprintf(stderr, fmt, parameters); | |
104 | va_end(parameters); | |
105 | putc('\n', stderr); | |
106 | fflush(stderr); | |
107 | } | |
108 | ||
109 | unsigned int get_error_count(void) | |
110 | { | |
111 | return Common::Error_Context::get_error_count(); | |
112 | } | |
113 | ||
114 | unsigned int get_warning_count(void) | |
115 | { | |
116 | return Common::Error_Context::get_warning_count(); | |
117 | } | |
118 | ||
119 | void path_error(const char *fmt, ...) | |
120 | { | |
121 | va_list ap; | |
122 | va_start(ap, fmt); | |
123 | char *err_msg = mprintf_va_list(fmt, ap); | |
124 | va_end(ap); | |
125 | ERROR("%s", err_msg); | |
126 | Free(err_msg); | |
127 | } | |
128 | ||
129 | namespace Common { | |
130 | ||
131 | unsigned int Error_Context::error_count = 0, Error_Context::warning_count = 0; | |
132 | unsigned int Error_Context::max_errors = (unsigned)-1; | |
133 | ||
134 | bool Error_Context::chain_printed = false; | |
135 | ||
136 | Error_Context *Error_Context::head = 0, *Error_Context::tail = 0; | |
137 | ||
138 | void Error_Context::print_context(FILE *fp) | |
139 | { | |
140 | int level = 0; | |
141 | for (Error_Context *ptr = head; ptr; ptr = ptr->next) { | |
142 | if (ptr->is_restorer) FATAL_ERROR("Error_Context::print()"); | |
143 | else if (!ptr->str) continue; | |
144 | else if (!ptr->is_printed) { | |
145 | for (int i = 0; i < level; i++) putc(' ', fp); | |
146 | if (ptr->location) ptr->location->print_location(fp); | |
147 | if (gcc_compat) fputs("note: ", fp); // CDT ignores "note" | |
148 | fputs(ptr->str, fp); | |
149 | fputs(":\n", fp); | |
150 | ptr->is_printed = true; | |
151 | } | |
152 | level++; | |
153 | } | |
154 | for (int i = 0; i < level; i++) putc(' ', fp); | |
155 | chain_printed = true; | |
156 | } | |
157 | ||
158 | Error_Context::Error_Context(size_t n_keep) | |
159 | : prev(0), next(0), location(0), str(0), is_printed(false), | |
160 | is_restorer(true), outer_printed(false) | |
161 | { | |
162 | Error_Context *begin = head; | |
163 | for (size_t i = 0; i < n_keep; i++) { | |
164 | if (!begin) break; | |
165 | begin = begin->next; | |
166 | } | |
167 | if (begin == head) { | |
168 | // complete backup | |
169 | next = head; | |
170 | head = 0; | |
171 | prev = tail; | |
172 | tail = 0; | |
173 | } else { | |
174 | // partial backup (only elements before begin are kept) | |
175 | next = begin; | |
176 | if (begin) { | |
177 | prev = tail; | |
178 | tail = begin->prev; | |
179 | tail->next = 0; | |
180 | begin->prev = 0; | |
181 | } else prev = 0; | |
182 | } | |
183 | outer_printed = chain_printed; | |
184 | chain_printed = false; | |
185 | } | |
186 | ||
187 | Error_Context::Error_Context(const Location *p_location) | |
188 | : prev(0), next(0), location(p_location), str(0), is_printed(false), | |
189 | is_restorer(false), outer_printed(false) | |
190 | { | |
191 | if (!head) head = this; | |
192 | if (tail) tail->next = this; | |
193 | prev = tail; | |
194 | next = 0; | |
195 | tail = this; | |
196 | } | |
197 | ||
198 | Error_Context::Error_Context(const Location *p_location, | |
199 | const char *p_fmt, ...) | |
200 | : prev(0), next(0), location(p_location), str(0), is_printed(false), | |
201 | is_restorer(false), outer_printed(false) | |
202 | { | |
203 | va_list args; | |
204 | va_start(args, p_fmt); | |
205 | str = mprintf_va_list(p_fmt, args); | |
206 | va_end(args); | |
207 | ||
208 | if (!head) head = this; | |
209 | if (tail) tail->next = this; | |
210 | prev = tail; | |
211 | next = 0; | |
212 | tail = this; | |
213 | } | |
214 | ||
215 | Error_Context::~Error_Context() | |
216 | { | |
217 | if (is_restorer) { | |
218 | if (chain_printed) { | |
219 | for (Error_Context *ptr = next; ptr; ptr = ptr->next) | |
220 | ptr->is_printed = false; | |
221 | } else chain_printed = outer_printed; | |
222 | if (head) { | |
223 | // partial restoration | |
224 | if (next) { | |
225 | tail->next = next; | |
226 | next->prev = tail; | |
227 | tail = prev; | |
228 | } | |
229 | } else { | |
230 | // full restoration | |
231 | head = next; | |
232 | tail = prev; | |
233 | } | |
234 | } else { | |
235 | Free(str); | |
236 | if (tail != this) FATAL_ERROR("Error_Context::~Error_Context()"); | |
237 | if (prev) prev->next = 0; | |
238 | else head = 0; | |
239 | tail = prev; | |
240 | } | |
241 | } | |
242 | ||
243 | void Error_Context::set_message(const char *p_fmt, ...) | |
244 | { | |
245 | if (is_restorer) FATAL_ERROR("Error_Context::set_message()"); | |
246 | Free(str); | |
247 | va_list args; | |
248 | va_start(args, p_fmt); | |
249 | str = mprintf_va_list(p_fmt, args); | |
250 | va_end(args); | |
251 | is_printed = false; | |
252 | } | |
253 | ||
254 | void Error_Context::report_error(const Location *loc, const char *fmt, | |
255 | va_list args) | |
256 | { | |
257 | if (!suppress_context) print_context(stderr); | |
258 | Location my_location; | |
259 | if (tail != 0 && loc && loc->get_filename() == 0) { | |
260 | // borrow location information from the innermost context | |
261 | my_location.set_location( *(tail->location) ); | |
262 | loc = &my_location; | |
263 | } | |
264 | if (loc) loc->print_location(stderr); | |
265 | fputs("error: ", stderr); | |
266 | vfprintf(stderr, fmt, args); | |
267 | putc('\n', stderr); | |
268 | fflush(stderr); | |
269 | increment_error_count(); | |
270 | } | |
271 | ||
272 | void Error_Context::report_warning(const Location *loc, const char *fmt, | |
273 | va_list args) | |
274 | { | |
275 | if(!(verb_level & 2)) return; | |
276 | if (!suppress_context) print_context(stderr); | |
277 | if (loc) loc->print_location(stderr); | |
278 | fputs("warning: ", stderr); | |
279 | vfprintf(stderr, fmt, args); | |
280 | putc('\n', stderr); | |
281 | fflush(stderr); | |
282 | increment_warning_count(); | |
283 | } | |
284 | ||
285 | void Error_Context::report_note(const Location *loc, const char *fmt, | |
286 | va_list args) | |
287 | { | |
288 | if (!suppress_context) print_context(stderr); | |
289 | if (loc) loc->print_location(stderr); | |
290 | fputs("note: ", stderr); | |
291 | vfprintf(stderr, fmt, args); | |
292 | putc('\n', stderr); | |
293 | fflush(stderr); | |
294 | } | |
295 | ||
296 | void Error_Context::increment_error_count() | |
297 | { | |
298 | if (++error_count >= max_errors) { | |
299 | fputs("Maximum number of errors reached, aborting.\n", stderr); | |
300 | fflush(stderr); | |
301 | abort(); | |
302 | } | |
303 | } | |
304 | ||
305 | void Error_Context::increment_warning_count() | |
306 | { | |
307 | warning_count++; | |
308 | } | |
309 | ||
310 | void Error_Context::print_error_statistics() | |
311 | { | |
312 | if (error_count == 0) { | |
313 | if (warning_count == 0) NOTIFY("No errors or warnings were detected."); | |
314 | else NOTIFY("No errors and %u warning%s were detected.", | |
315 | warning_count, warning_count > 1 ? "s" : ""); | |
316 | } else { | |
317 | if (warning_count == 0) NOTIFY("%u error%s and no warnings were " | |
318 | "detected.", error_count, error_count > 1 ? "s" : ""); | |
319 | else NOTIFY("%u error%s and %u warning%s were detected.", | |
320 | error_count, error_count > 1 ? "s" : "", | |
321 | warning_count, warning_count > 1 ? "s" : ""); | |
322 | } | |
323 | } | |
324 | ||
325 | } // namespace Common |