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