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