1 // Compiler implementation of the D programming language
2 // Copyright (c) 1999-2015 by Digital Mars
3 // All Rights Reserved
4 // written by Walter Bright
5 // http://www.digitalmars.com
6 // Distributed under the Boost Software License, Version 1.0.
7 // http://www.boost.org/LICENSE_1_0.txt
8 
9 module ddmd.errors;
10 
11 import core.stdc.stdarg, core.stdc.stdio, core.stdc.stdlib, core.stdc..string, core.sys.posix.unistd, core.sys.windows.windows;
12 import ddmd.globals, ddmd.root.outbuffer, ddmd.root.rmem;
13 
14 version (Windows) extern (C) int isatty(int);
15 version (Windows) alias _isatty = isatty;
16 version (Windows) int _fileno(FILE* f)
17 {
18     return f._file;
19 }
20 
21 enum COLOR : int
22 {
23     COLOR_BLACK = 0,
24     COLOR_RED = 1,
25     COLOR_GREEN = 2,
26     COLOR_BLUE = 4,
27     COLOR_YELLOW = COLOR_RED | COLOR_GREEN,
28     COLOR_MAGENTA = COLOR_RED | COLOR_BLUE,
29     COLOR_CYAN = COLOR_GREEN | COLOR_BLUE,
30     COLOR_WHITE = COLOR_RED | COLOR_GREEN | COLOR_BLUE,
31 }
32 
33 alias COLOR_BLACK = COLOR.COLOR_BLACK;
34 alias COLOR_RED = COLOR.COLOR_RED;
35 alias COLOR_GREEN = COLOR.COLOR_GREEN;
36 alias COLOR_BLUE = COLOR.COLOR_BLUE;
37 alias COLOR_YELLOW = COLOR.COLOR_YELLOW;
38 alias COLOR_MAGENTA = COLOR.COLOR_MAGENTA;
39 alias COLOR_CYAN = COLOR.COLOR_CYAN;
40 alias COLOR_WHITE = COLOR.COLOR_WHITE;
41 
42 version (Windows)
43 {
44     extern (C++) static WORD consoleAttributes(HANDLE h)
45     {
46         static __gshared CONSOLE_SCREEN_BUFFER_INFO sbi;
47         static __gshared bool sbi_inited = false;
48         if (!sbi_inited)
49             sbi_inited = GetConsoleScreenBufferInfo(h, &sbi) != FALSE;
50         return sbi.wAttributes;
51     }
52 
53     enum : int
54     {
55         FOREGROUND_WHITE = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,
56     }
57 }
58 
59 extern (C++) bool isConsoleColorSupported()
60 {
61     version (Windows)
62     {
63         return _isatty(_fileno(stderr)) != 0;
64     }
65     else static if (__linux__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun)
66     {
67         const(char)* term = getenv("TERM");
68         return isatty(STDERR_FILENO) && term && term[0] && 0 != strcmp(term, "dumb");
69     }
70     else
71     {
72         return false;
73     }
74 }
75 
76 extern (C++) void setConsoleColorBright(bool bright)
77 {
78     version (Windows)
79     {
80         HANDLE h = GetStdHandle(STD_ERROR_HANDLE);
81         WORD attr = consoleAttributes(h);
82         SetConsoleTextAttribute(h, attr | (bright ? FOREGROUND_INTENSITY : 0));
83     }
84     else
85     {
86         fprintf(stderr, "\033[%dm", bright ? 1 : 0);
87     }
88 }
89 
90 extern (C++) void setConsoleColor(COLOR color, bool bright)
91 {
92     version (Windows)
93     {
94         HANDLE h = GetStdHandle(STD_ERROR_HANDLE);
95         WORD attr = consoleAttributes(h);
96         attr = (attr & ~(FOREGROUND_WHITE | FOREGROUND_INTENSITY)) | ((color & COLOR_RED) ? FOREGROUND_RED : 0) | ((color & COLOR_GREEN) ? FOREGROUND_GREEN : 0) | ((color & COLOR_BLUE) ? FOREGROUND_BLUE : 0) | (bright ? FOREGROUND_INTENSITY : 0);
97         SetConsoleTextAttribute(h, attr);
98     }
99     else
100     {
101         fprintf(stderr, "\033[%d;%dm", bright ? 1 : 0, 30 + cast(int)color);
102     }
103 }
104 
105 extern (C++) void resetConsoleColor()
106 {
107     version (Windows)
108     {
109         HANDLE h = GetStdHandle(STD_ERROR_HANDLE);
110         SetConsoleTextAttribute(h, consoleAttributes(h));
111     }
112     else
113     {
114         fprintf(stderr, "\033[m");
115     }
116 }
117 
118 /**************************************
119  * Print error message
120  */
121 extern (C++) void error(Loc loc, const(char)* format, ...)
122 {
123     va_list ap;
124     va_start(ap, format);
125     verror(loc, format, ap);
126     va_end(ap);
127 }
128 
129 extern (C++) void error(const(char)* filename, uint linnum, uint charnum, const(char)* format, ...)
130 {
131     Loc loc;
132     loc.filename = cast(char*)filename;
133     loc.linnum = linnum;
134     loc.charnum = charnum;
135     va_list ap;
136     va_start(ap, format);
137     verror(loc, format, ap);
138     va_end(ap);
139 }
140 
141 extern (C++) void errorSupplemental(Loc loc, const(char)* format, ...)
142 {
143     va_list ap;
144     va_start(ap, format);
145     verrorSupplemental(loc, format, ap);
146     va_end(ap);
147 }
148 
149 extern (C++) void warning(Loc loc, const(char)* format, ...)
150 {
151     va_list ap;
152     va_start(ap, format);
153     vwarning(loc, format, ap);
154     va_end(ap);
155 }
156 
157 extern (C++) void warningSupplemental(Loc loc, const(char)* format, ...)
158 {
159     va_list ap;
160     va_start(ap, format);
161     vwarningSupplemental(loc, format, ap);
162     va_end(ap);
163 }
164 
165 extern (C++) void deprecation(Loc loc, const(char)* format, ...)
166 {
167     va_list ap;
168     va_start(ap, format);
169     vdeprecation(loc, format, ap);
170     va_end(ap);
171 }
172 
173 extern (C++) void deprecationSupplemental(Loc loc, const(char)* format, ...)
174 {
175     va_list ap;
176     va_start(ap, format);
177     vdeprecation(loc, format, ap);
178     va_end(ap);
179 }
180 
181 // Just print, doesn't care about gagging
182 extern (C++) void verrorPrint(Loc loc, COLOR headerColor, const(char)* header, const(char)* format, va_list ap, const(char)* p1 = null, const(char)* p2 = null)
183 {
184     char* p = loc.toChars();
185     if (global.params.color)
186         setConsoleColorBright(true);
187     if (*p)
188         fprintf(stderr, "%s: ", p);
189     mem.xfree(p);
190     if (global.params.color)
191         setConsoleColor(headerColor, true);
192     fputs(header, stderr);
193     if (global.params.color)
194         resetConsoleColor();
195     if (p1)
196         fprintf(stderr, "%s ", p1);
197     if (p2)
198         fprintf(stderr, "%s ", p2);
199     OutBuffer tmp;
200     tmp.vprintf(format, ap);
201     fprintf(stderr, "%s\n", tmp.peekString());
202     fflush(stderr);
203 }
204 
205 // header is "Error: " by default (see errors.h)
206 extern (C++) void verror(Loc loc, const(char)* format, va_list ap, const(char)* p1 = null, const(char)* p2 = null, const(char)* header = "Error: ")
207 {
208     global.errors++;
209     if (!global.gag)
210     {
211         verrorPrint(loc, COLOR_RED, header, format, ap, p1, p2);
212         if (global.errorLimit && global.errors >= global.errorLimit)
213             fatal(); // moderate blizzard of cascading messages
214     }
215     else
216     {
217         //fprintf(stderr, "(gag:%d) ", global.gag);
218         //verrorPrint(loc, COLOR_RED, header, format, ap, p1, p2);
219         global.gaggedErrors++;
220     }
221 }
222 
223 // Doesn't increase error count, doesn't print "Error:".
224 extern (C++) void verrorSupplemental(Loc loc, const(char)* format, va_list ap)
225 {
226     if (!global.gag)
227         verrorPrint(loc, COLOR_RED, "       ", format, ap);
228 }
229 
230 extern (C++) void vwarning(Loc loc, const(char)* format, va_list ap)
231 {
232     if (global.params.warnings && !global.gag)
233     {
234         verrorPrint(loc, COLOR_YELLOW, "Warning: ", format, ap);
235         //halt();
236         if (global.params.warnings == 1)
237             global.warnings++; // warnings don't count if gagged
238     }
239 }
240 
241 extern (C++) void vwarningSupplemental(Loc loc, const(char)* format, va_list ap)
242 {
243     if (global.params.warnings && !global.gag)
244         verrorPrint(loc, COLOR_YELLOW, "       ", format, ap);
245 }
246 
247 extern (C++) void vdeprecation(Loc loc, const(char)* format, va_list ap, const(char)* p1 = null, const(char)* p2 = null)
248 {
249     static __gshared const(char)* header = "Deprecation: ";
250     if (global.params.useDeprecated == 0)
251         verror(loc, format, ap, p1, p2, header);
252     else if (global.params.useDeprecated == 2 && !global.gag)
253         verrorPrint(loc, COLOR_BLUE, header, format, ap, p1, p2);
254 }
255 
256 extern (C++) void vdeprecationSupplemental(Loc loc, const(char)* format, va_list ap)
257 {
258     if (global.params.useDeprecated == 0)
259         verrorSupplemental(loc, format, ap);
260     else if (global.params.useDeprecated == 2 && !global.gag)
261         verrorPrint(loc, COLOR_BLUE, "       ", format, ap);
262 }
263 
264 /***************************************
265  * Call this after printing out fatal error messages to clean up and exit
266  * the compiler.
267  */
268 extern (C++) void fatal()
269 {
270     version (none)
271     {
272         halt();
273     }
274     exit(EXIT_FAILURE);
275 }
276 
277 /**************************************
278  * Try to stop forgetting to remove the breakpoints from
279  * release builds.
280  */
281 extern (C++) void halt()
282 {
283     debug
284     {
285         *cast(char*)0 = 0;
286     }
287 }