]> git.sur5r.net Git - cc65/blob - src/ca65/error.c
Limit the number of additional line infos printed in case of an error or
[cc65] / src / ca65 / error.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                  error.c                                  */
4 /*                                                                           */
5 /*                Error handling for the ca65 macroassembler                 */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2011, Ullrich von Bassewitz                                      */
10 /*                Roemerstrasse 52                                           */
11 /*                D-70794 Filderstadt                                        */
12 /* EMail:         uz@cc65.org                                                */
13 /*                                                                           */
14 /*                                                                           */
15 /* This software is provided 'as-is', without any expressed or implied       */
16 /* warranty.  In no event will the authors be held liable for any damages    */
17 /* arising from the use of this software.                                    */
18 /*                                                                           */
19 /* Permission is granted to anyone to use this software for any purpose,     */
20 /* including commercial applications, and to alter it and redistribute it    */
21 /* freely, subject to the following restrictions:                            */
22 /*                                                                           */
23 /* 1. The origin of this software must not be misrepresented; you must not   */
24 /*    claim that you wrote the original software. If you use this software   */
25 /*    in a product, an acknowledgment in the product documentation would be  */
26 /*    appreciated but is not required.                                       */
27 /* 2. Altered source versions must be plainly marked as such, and must not   */
28 /*    be misrepresented as being the original software.                      */
29 /* 3. This notice may not be removed or altered from any source              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <stdarg.h>
39
40 /* common */
41 #include "strbuf.h"
42
43 /* ca65 */
44 #include "error.h"
45 #include "filetab.h"
46 #include "lineinfo.h"
47 #include "nexttok.h"
48
49
50
51 /*****************************************************************************/
52 /*                                   Data                                    */
53 /*****************************************************************************/
54
55
56
57 /* Warning level */
58 unsigned WarnLevel      = 1;
59
60 /* Statistics */
61 unsigned ErrorCount     = 0;
62 unsigned WarningCount   = 0;
63
64
65
66 /*****************************************************************************/
67 /*                             Helper functions                              */
68 /*****************************************************************************/
69
70
71
72 static void VPrintMsg (const FilePos* Pos, const char* Desc,
73                        const char* Format, va_list ap)
74 /* Format and output an error/warning message. */
75 {
76     StrBuf S = STATIC_STRBUF_INITIALIZER;
77
78     /* Format the actual message */
79     StrBuf Msg = STATIC_STRBUF_INITIALIZER;
80     SB_VPrintf (&Msg, Format, ap);
81     SB_Terminate (&Msg);
82
83     /* Format the message header */
84     SB_Printf (&S, "%s(%lu): %s: ",
85                SB_GetConstBuf (GetFileName (Pos->Name)),
86                Pos->Line,
87                Desc);
88
89     /* Append the message to the message header */
90     SB_Append (&S, &Msg);
91
92     /* Delete the formatted message */
93     SB_Done (&Msg);
94
95     /* Add a new line and terminate the generated full message */
96     SB_AppendChar (&S, '\n');
97     SB_Terminate (&S);
98
99     /* Output the full message */
100     fputs (SB_GetConstBuf (&S), stderr);
101
102     /* Delete the buffer for the full message */
103     SB_Done (&S);
104 }
105
106
107
108 static void PrintMsg (const FilePos* Pos, const char* Desc,
109                       const char* Format, ...)
110 /* Format and output an error/warning message. */
111 {
112     va_list ap;
113     va_start (ap, Format);
114     VPrintMsg (Pos, Desc, Format, ap);
115     va_end (ap);
116 }
117
118
119
120 static void AddNotifications (const Collection* LineInfos)
121 /* Output additional notifications for an error or warning */
122 {
123     unsigned I;
124     unsigned Skipped;
125
126     /* The basic line info is always in slot zero. It has been used to
127      * output the actual error or warning. The following slots may contain
128      * more information. Check them and print additional notifications if
129      * they're present, but limit the number to a reasonable value.
130      */
131     unsigned MaxCount = CollCount (LineInfos);
132     if (MaxCount > 6) {
133         MaxCount = 6;
134     }               
135     Skipped = CollCount (LineInfos) - MaxCount;
136     for (I = 1; I < MaxCount; ++I) {
137         /* Get next line info */
138         const LineInfo* LI = CollConstAt (LineInfos, I);
139         /* Check the type and output an appropriate note */
140         unsigned Type = GetLineInfoType (LI);
141         if (Type == LI_TYPE_EXT) {
142             PrintMsg (GetSourcePos (LI), "Note",
143                       "Assembler code generated from this line");
144         } else if (Type == LI_TYPE_MACRO) {
145             PrintMsg (GetSourcePos (LI), "Note",
146                       "Macro was defined here");
147         }
148     }
149
150     /* Add a note if we have more stuff that we won't output */
151     if (Skipped > 0) {
152         PrintMsg (GetSourcePos (CollConstAt (LineInfos, 0)), "Note",
153                   "Dropping %u additional line infos", Skipped);
154     }
155 }
156
157
158
159 /*****************************************************************************/
160 /*                                 Warnings                                  */
161 /*****************************************************************************/
162
163
164
165 static void WarningMsg (const Collection* LineInfos, const char* Format, va_list ap)
166 /* Print warning message. */
167 {
168     /* The first entry in the collection is that of the actual source pos */
169     const LineInfo* LI = CollConstAt (LineInfos, 0);
170
171     /* Output a warning for this position */
172     VPrintMsg (GetSourcePos (LI), "Warning", Format, ap);
173
174     /* Add additional notifications if necessary */
175     AddNotifications (LineInfos);
176
177     /* Count warnings */
178     ++WarningCount;
179 }
180
181
182
183 void Warning (unsigned Level, const char* Format, ...)
184 /* Print warning message. */
185 {
186     if (Level <= WarnLevel) {
187
188         va_list ap;
189         Collection LineInfos = STATIC_COLLECTION_INITIALIZER;
190
191         /* Get line infos for the current position */
192         GetFullLineInfo (&LineInfos, 0);
193
194         /* Output the message */
195         va_start (ap, Format);
196         WarningMsg (&LineInfos, Format, ap);
197         va_end (ap);
198
199         /* Free the line info list */
200         DoneCollection (&LineInfos);
201     }
202 }
203
204
205
206 void PWarning (const FilePos* Pos, unsigned Level, const char* Format, ...)
207 /* Print warning message giving an explicit file and position. */
208 {
209     if (Level <= WarnLevel) {
210         va_list ap;
211         va_start (ap, Format);
212         VPrintMsg (Pos, "Warning", Format, ap);
213         va_end (ap);
214
215         /* Count warnings */
216         ++WarningCount;
217     }
218 }
219
220
221
222 void LIWarning (const Collection* LineInfos, unsigned Level, const char* Format, ...)
223 /* Print warning message using the given line infos */
224 {
225     if (Level <= WarnLevel) {
226         /* Output the message */
227         va_list ap;
228         va_start (ap, Format);
229         WarningMsg (LineInfos, Format, ap);
230         va_end (ap);
231     }
232 }
233
234
235
236 /*****************************************************************************/
237 /*                                  Errors                                   */
238 /*****************************************************************************/
239
240
241
242 void ErrorMsg (const Collection* LineInfos, const char* Format, va_list ap)
243 /* Print an error message */
244 {
245     /* The first entry in the collection is that of the actual source pos */
246     const LineInfo* LI = CollConstAt (LineInfos, 0);
247
248     /* Output an error for this position */
249     VPrintMsg (GetSourcePos (LI), "Error", Format, ap);
250
251     /* Add additional notifications if necessary */
252     AddNotifications (LineInfos);
253
254     /* Count errors */
255     ++ErrorCount;
256 }
257
258
259
260 void Error (const char* Format, ...)
261 /* Print an error message */
262 {
263     va_list ap;
264     Collection LineInfos = STATIC_COLLECTION_INITIALIZER;
265
266     /* Get line infos for the current position */
267     GetFullLineInfo (&LineInfos, 0);
268
269     /* Output the message */
270     va_start (ap, Format);
271     ErrorMsg (&LineInfos, Format, ap);
272     va_end (ap);
273
274     /* Free the line info list */
275     DoneCollection (&LineInfos);
276 }
277
278
279
280 void LIError (const Collection* LineInfos, const char* Format, ...)
281 /* Print an error message using the given line infos. */
282 {
283     /* Output an error for this position */
284     va_list ap;
285     va_start (ap, Format);
286     ErrorMsg (LineInfos, Format, ap);
287     va_end (ap);
288 }
289
290
291
292 void ErrorSkip (const char* Format, ...)
293 /* Print an error message and skip the rest of the line */
294 {
295     va_list ap;
296     Collection LineInfos = STATIC_COLLECTION_INITIALIZER;
297
298     /* Get line infos for the current position */
299     GetFullLineInfo (&LineInfos, 0);
300
301     /* Output the message */
302     va_start (ap, Format);
303     ErrorMsg (&LineInfos, Format, ap);
304     va_end (ap);
305
306     /* Free the line info list */
307     DoneCollection (&LineInfos);
308
309     /* Skip tokens until we reach the end of the line */
310     SkipUntilSep ();
311 }
312
313
314
315 /*****************************************************************************/
316 /*                                   Code                                    */
317 /*****************************************************************************/
318
319
320
321 void Fatal (const char* Format, ...)
322 /* Print a message about a fatal error and die */
323 {
324     va_list ap;
325     StrBuf S = STATIC_STRBUF_INITIALIZER;
326
327     va_start (ap, Format);
328     SB_VPrintf (&S, Format, ap);
329     SB_Terminate (&S);
330     va_end (ap);
331
332     fprintf (stderr, "Fatal error: %s\n", SB_GetConstBuf (&S));
333
334     SB_Done (&S);
335
336     /* And die... */
337     exit (EXIT_FAILURE);
338 }
339
340
341
342 void Internal (const char* Format, ...)
343 /* Print a message about an internal assembler error and die. */
344 {
345     va_list ap;
346     StrBuf S = STATIC_STRBUF_INITIALIZER;
347
348     va_start (ap, Format);
349     SB_VPrintf (&S, Format, ap);
350     SB_Terminate (&S);
351     va_end (ap);
352
353     fprintf (stderr, "Internal assembler error: %s\n", SB_GetConstBuf (&S));
354
355     SB_Done (&S);
356
357     exit (EXIT_FAILURE);
358 }
359
360
361