1 | // Copyright (c) Athena Dev Teams - Licensed under GNU GPL |
---|
2 | // For more information, see LICENCE in the main folder |
---|
3 | |
---|
4 | #include "../common/cbasetypes.h" |
---|
5 | #include "../common/strlib.h" // StringBuf |
---|
6 | #include "showmsg.h" |
---|
7 | |
---|
8 | #include <stdio.h> |
---|
9 | #include <string.h> |
---|
10 | #include <stdarg.h> |
---|
11 | #include <time.h> |
---|
12 | #include <stdlib.h> // atexit |
---|
13 | |
---|
14 | #ifdef WIN32 |
---|
15 | #define WIN32_LEAN_AND_MEAN |
---|
16 | #include <windows.h> |
---|
17 | |
---|
18 | #ifdef DEBUGLOGMAP |
---|
19 | #define DEBUGLOGPATH "log\\map-server.log" |
---|
20 | #else |
---|
21 | #ifdef DEBUGLOGCHAR |
---|
22 | #define DEBUGLOGPATH "log\\char-server.log" |
---|
23 | #else |
---|
24 | #ifdef DEBUGLOGLOGIN |
---|
25 | #define DEBUGLOGPATH "log\\login-server.log" |
---|
26 | #endif |
---|
27 | #endif |
---|
28 | #endif |
---|
29 | #else |
---|
30 | #include <unistd.h> |
---|
31 | |
---|
32 | #ifdef DEBUGLOGMAP |
---|
33 | #define DEBUGLOGPATH "log/map-server.log" |
---|
34 | #else |
---|
35 | #ifdef DEBUGLOGCHAR |
---|
36 | #define DEBUGLOGPATH "log/char-server.log" |
---|
37 | #else |
---|
38 | #ifdef DEBUGLOGLOGIN |
---|
39 | #define DEBUGLOGPATH "log/login-server.log" |
---|
40 | #endif |
---|
41 | #endif |
---|
42 | #endif |
---|
43 | #endif |
---|
44 | |
---|
45 | /////////////////////////////////////////////////////////////////////////////// |
---|
46 | /// behavioral parameter. |
---|
47 | /// when redirecting output: |
---|
48 | /// if true prints escape sequences |
---|
49 | /// if false removes the escape sequences |
---|
50 | int stdout_with_ansisequence = 0; |
---|
51 | |
---|
52 | int msg_silent = 0; //Specifies how silent the console is. |
---|
53 | |
---|
54 | /////////////////////////////////////////////////////////////////////////////// |
---|
55 | /// static/dynamic buffer for the messages |
---|
56 | |
---|
57 | #define SBUF_SIZE 2048 // never put less that what's required for the debug message |
---|
58 | |
---|
59 | #define NEWBUF(buf) \ |
---|
60 | struct { \ |
---|
61 | char s_[SBUF_SIZE]; \ |
---|
62 | StringBuf *d_; \ |
---|
63 | char *v_; \ |
---|
64 | int l_; \ |
---|
65 | } buf ={"",NULL,NULL,0}; \ |
---|
66 | //define NEWBUF |
---|
67 | |
---|
68 | #define BUFVPRINTF(buf,fmt,args) \ |
---|
69 | buf.l_ = vsnprintf(buf.s_, SBUF_SIZE, fmt, args); \ |
---|
70 | if( buf.l_ >= 0 && buf.l_ < SBUF_SIZE ) \ |
---|
71 | {/* static buffer */ \ |
---|
72 | buf.v_ = buf.s_; \ |
---|
73 | } \ |
---|
74 | else \ |
---|
75 | {/* dynamic buffer */ \ |
---|
76 | buf.d_ = StringBuf_Malloc(); \ |
---|
77 | buf.l_ = StringBuf_Vprintf(buf.d_, fmt, args); \ |
---|
78 | buf.v_ = StringBuf_Value(buf.d_); \ |
---|
79 | ShowDebug("showmsg: dynamic buffer used, increase the static buffer size to %d or more.\n", buf.l_+1);\ |
---|
80 | } \ |
---|
81 | //define BUFVPRINTF |
---|
82 | |
---|
83 | #define BUFVAL(buf) buf.v_ |
---|
84 | #define BUFLEN(buf) buf.l_ |
---|
85 | |
---|
86 | #define FREEBUF(buf) \ |
---|
87 | if( buf.d_ ) \ |
---|
88 | { \ |
---|
89 | StringBuf_Free(buf.d_); \ |
---|
90 | buf.d_ = NULL; \ |
---|
91 | } \ |
---|
92 | buf.v_ = NULL; \ |
---|
93 | //define FREEBUF |
---|
94 | |
---|
95 | /////////////////////////////////////////////////////////////////////////////// |
---|
96 | #ifdef _WIN32 |
---|
97 | // XXX adapted from eApp (comments are left untouched) [flaviojs] |
---|
98 | |
---|
99 | /////////////////////////////////////////////////////////////////////////////// |
---|
100 | // ansi compatible printf with control sequence parser for windows |
---|
101 | // fast hack, handle with care, not everything implemented |
---|
102 | // |
---|
103 | // \033[#;...;#m - Set Graphics Rendition (SGR) |
---|
104 | // |
---|
105 | // printf("\x1b[1;31;40m"); // Bright red on black |
---|
106 | // printf("\x1b[3;33;45m"); // Blinking yellow on magenta (blink not implemented) |
---|
107 | // printf("\x1b[1;30;47m"); // Bright black (grey) on dim white |
---|
108 | // |
---|
109 | // Style Foreground Background |
---|
110 | // 1st Digit 2nd Digit 3rd Digit RGB |
---|
111 | // 0 - Reset 30 - Black 40 - Black 000 |
---|
112 | // 1 - FG Bright 31 - Red 41 - Red 100 |
---|
113 | // 2 - Unknown 32 - Green 42 - Green 010 |
---|
114 | // 3 - Blink 33 - Yellow 43 - Yellow 110 |
---|
115 | // 4 - Underline 34 - Blue 44 - Blue 001 |
---|
116 | // 5 - BG Bright 35 - Magenta 45 - Magenta 101 |
---|
117 | // 6 - Unknown 36 - Cyan 46 - Cyan 011 |
---|
118 | // 7 - Reverse 37 - White 47 - White 111 |
---|
119 | // 8 - Concealed (invisible) |
---|
120 | // |
---|
121 | // \033[#A - Cursor Up (CUU) |
---|
122 | // Moves the cursor up by the specified number of lines without changing columns. |
---|
123 | // If the cursor is already on the top line, this sequence is ignored. \e[A is equivalent to \e[1A. |
---|
124 | // |
---|
125 | // \033[#B - Cursor Down (CUD) |
---|
126 | // Moves the cursor down by the specified number of lines without changing columns. |
---|
127 | // If the cursor is already on the bottom line, this sequence is ignored. \e[B is equivalent to \e[1B. |
---|
128 | // |
---|
129 | // \033[#C - Cursor Forward (CUF) |
---|
130 | // Moves the cursor forward by the specified number of columns without changing lines. |
---|
131 | // If the cursor is already in the rightmost column, this sequence is ignored. \e[C is equivalent to \e[1C. |
---|
132 | // |
---|
133 | // \033[#D - Cursor Backward (CUB) |
---|
134 | // Moves the cursor back by the specified number of columns without changing lines. |
---|
135 | // If the cursor is already in the leftmost column, this sequence is ignored. \e[D is equivalent to \e[1D. |
---|
136 | // |
---|
137 | // \033[#E - Cursor Next Line (CNL) |
---|
138 | // Moves the cursor down the indicated # of rows, to column 1. \e[E is equivalent to \e[1E. |
---|
139 | // |
---|
140 | // \033[#F - Cursor Preceding Line (CPL) |
---|
141 | // Moves the cursor up the indicated # of rows, to column 1. \e[F is equivalent to \e[1F. |
---|
142 | // |
---|
143 | // \033[#G - Cursor Horizontal Absolute (CHA) |
---|
144 | // Moves the cursor to indicated column in current row. \e[G is equivalent to \e[1G. |
---|
145 | // |
---|
146 | // \033[#;#H - Cursor Position (CUP) |
---|
147 | // Moves the cursor to the specified position. The first # specifies the line number, |
---|
148 | // the second # specifies the column. If you do not specify a position, the cursor moves to the home position: |
---|
149 | // the upper-left corner of the screen (line 1, column 1). |
---|
150 | // |
---|
151 | // \033[#;#f - Horizontal & Vertical Position |
---|
152 | // (same as \033[#;#H) |
---|
153 | // |
---|
154 | // \033[s - Save Cursor Position (SCP) |
---|
155 | // The current cursor position is saved. |
---|
156 | // |
---|
157 | // \033[u - Restore cursor position (RCP) |
---|
158 | // Restores the cursor position saved with the (SCP) sequence \033[s. |
---|
159 | // (addition, restore to 0,0 if nothinh was saved before) |
---|
160 | // |
---|
161 | |
---|
162 | // \033[#J - Erase Display (ED) |
---|
163 | // Clears the screen and moves to the home position |
---|
164 | // \033[0J - Clears the screen from cursor to end of display. The cursor position is unchanged. (default) |
---|
165 | // \033[1J - Clears the screen from start to cursor. The cursor position is unchanged. |
---|
166 | // \033[2J - Clears the screen and moves the cursor to the home position (line 1, column 1). |
---|
167 | // |
---|
168 | // \033[#K - Erase Line (EL) |
---|
169 | // Clears the current line from the cursor position |
---|
170 | // \033[0K - Clears all characters from the cursor position to the end of the line (including the character at the cursor position). The cursor position is unchanged. (default) |
---|
171 | // \033[1K - Clears all characters from start of line to the cursor position. (including the character at the cursor position). The cursor position is unchanged. |
---|
172 | // \033[2K - Clears all characters of the whole line. The cursor position is unchanged. |
---|
173 | |
---|
174 | |
---|
175 | /* |
---|
176 | not implemented |
---|
177 | |
---|
178 | \033[#L |
---|
179 | IL: Insert Lines: The cursor line and all lines below it move down # lines, leaving blank space. The cursor position is unchanged. The bottommost # lines are lost. \e[L is equivalent to \e[1L. |
---|
180 | \033[#M |
---|
181 | DL: Delete Line: The block of # lines at and below the cursor are deleted; all lines below them move up # lines to fill in the gap, leaving # blank lines at the bottom of the screen. The cursor position is unchanged. \e[M is equivalent to \e[1M. |
---|
182 | \033[#\@ |
---|
183 | ICH: Insert CHaracter: The cursor character and all characters to the right of it move right # columns, leaving behind blank space. The cursor position is unchanged. The rightmost # characters on the line are lost. \e[\@ is equivalent to \e[1\@. |
---|
184 | \033[#P |
---|
185 | DCH: Delete CHaracter: The block of # characters at and to the right of the cursor are deleted; all characters to the right of it move left # columns, leaving behind blank space. The cursor position is unchanged. \e[P is equivalent to \e[1P. |
---|
186 | |
---|
187 | Escape sequences for Select Character Set |
---|
188 | */ |
---|
189 | |
---|
190 | #define is_console(handle) (FILE_TYPE_CHAR==GetFileType(handle)) |
---|
191 | |
---|
192 | /////////////////////////////////////////////////////////////////////////////// |
---|
193 | int VFPRINTF(HANDLE handle, const char *fmt, va_list argptr) |
---|
194 | { |
---|
195 | ///////////////////////////////////////////////////////////////// |
---|
196 | /* XXX Two streams are being used. Disabled to avoid inconsistency [flaviojs] |
---|
197 | static COORD saveposition = {0,0}; |
---|
198 | */ |
---|
199 | |
---|
200 | ///////////////////////////////////////////////////////////////// |
---|
201 | DWORD written; |
---|
202 | char *p, *q; |
---|
203 | NEWBUF(tempbuf); // temporary buffer |
---|
204 | |
---|
205 | if(!fmt || !*fmt) |
---|
206 | return 0; |
---|
207 | |
---|
208 | // Print everything to the buffer |
---|
209 | BUFVPRINTF(tempbuf,fmt,argptr); |
---|
210 | |
---|
211 | if( !is_console(handle) && stdout_with_ansisequence ) |
---|
212 | { |
---|
213 | WriteFile(handle, BUFVAL(tempbuf), BUFLEN(tempbuf), &written, 0); |
---|
214 | return 0; |
---|
215 | } |
---|
216 | |
---|
217 | // start with processing |
---|
218 | p = BUFVAL(tempbuf); |
---|
219 | while ((q = strchr(p, 0x1b)) != NULL) |
---|
220 | { // find the escape character |
---|
221 | if( 0==WriteConsole(handle, p, (DWORD)(q-p), &written, 0) ) // write up to the escape |
---|
222 | WriteFile(handle, p, (DWORD)(q-p), &written, 0); |
---|
223 | |
---|
224 | if( q[1]!='[' ) |
---|
225 | { // write the escape char (whatever purpose it has) |
---|
226 | if(0==WriteConsole(handle, q, 1, &written, 0) ) |
---|
227 | WriteFile(handle,q, 1, &written, 0); |
---|
228 | p=q+1; //and start searching again |
---|
229 | } |
---|
230 | else |
---|
231 | { // from here, we will skip the '\033[' |
---|
232 | // we break at the first unprocessible position |
---|
233 | // assuming regular text is starting there |
---|
234 | uint8 numbers[16], numpoint=0; |
---|
235 | CONSOLE_SCREEN_BUFFER_INFO info; |
---|
236 | |
---|
237 | // initialize |
---|
238 | GetConsoleScreenBufferInfo(handle, &info); |
---|
239 | memset(numbers,0,sizeof(numbers)); |
---|
240 | |
---|
241 | // skip escape and bracket |
---|
242 | q=q+2; |
---|
243 | for(;;) |
---|
244 | { |
---|
245 | if( ISDIGIT(*q) ) |
---|
246 | { // add number to number array, only accept 2digits, shift out the rest |
---|
247 | // so // \033[123456789m will become \033[89m |
---|
248 | numbers[numpoint] = (numbers[numpoint]<<4) | (*q-'0'); |
---|
249 | ++q; |
---|
250 | // and next character |
---|
251 | continue; |
---|
252 | } |
---|
253 | else if( *q == ';' ) |
---|
254 | { // delimiter |
---|
255 | if(numpoint<sizeof(numbers)/sizeof(*numbers)) |
---|
256 | { // go to next array position |
---|
257 | numpoint++; |
---|
258 | } |
---|
259 | else |
---|
260 | { // array is full, so we 'forget' the first value |
---|
261 | memmove(numbers,numbers+1,sizeof(numbers)/sizeof(*numbers)-1); |
---|
262 | numbers[sizeof(numbers)/sizeof(*numbers)-1]=0; |
---|
263 | } |
---|
264 | ++q; |
---|
265 | // and next number |
---|
266 | continue; |
---|
267 | } |
---|
268 | else if( *q == 'm' ) |
---|
269 | { // \033[#;...;#m - Set Graphics Rendition (SGR) |
---|
270 | uint8 i; |
---|
271 | for(i=0; i<= numpoint; ++i) |
---|
272 | { |
---|
273 | if( 0x00 == (0xF0 & numbers[i]) ) |
---|
274 | { // upper nibble 0 |
---|
275 | if( 0 == numbers[i] ) |
---|
276 | { // reset |
---|
277 | info.wAttributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; |
---|
278 | } |
---|
279 | else if( 1==numbers[i] ) |
---|
280 | { // set foreground intensity |
---|
281 | info.wAttributes |= FOREGROUND_INTENSITY; |
---|
282 | } |
---|
283 | else if( 5==numbers[i] ) |
---|
284 | { // set background intensity |
---|
285 | info.wAttributes |= BACKGROUND_INTENSITY; |
---|
286 | } |
---|
287 | else if( 7==numbers[i] ) |
---|
288 | { // reverse colors (just xor them) |
---|
289 | info.wAttributes ^= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | |
---|
290 | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE; |
---|
291 | } |
---|
292 | //case '2': // not existing |
---|
293 | //case '3': // blinking (not implemented) |
---|
294 | //case '4': // unterline (not implemented) |
---|
295 | //case '6': // not existing |
---|
296 | //case '8': // concealed (not implemented) |
---|
297 | //case '9': // not existing |
---|
298 | } |
---|
299 | else if( 0x20 == (0xF0 & numbers[i]) ) |
---|
300 | { // off |
---|
301 | |
---|
302 | if( 1==numbers[i] ) |
---|
303 | { // set foreground intensity off |
---|
304 | info.wAttributes &= ~FOREGROUND_INTENSITY; |
---|
305 | } |
---|
306 | else if( 5==numbers[i] ) |
---|
307 | { // set background intensity off |
---|
308 | info.wAttributes &= ~BACKGROUND_INTENSITY; |
---|
309 | } |
---|
310 | else if( 7==numbers[i] ) |
---|
311 | { // reverse colors (just xor them) |
---|
312 | info.wAttributes ^= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | |
---|
313 | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE; |
---|
314 | } |
---|
315 | } |
---|
316 | else if( 0x30 == (0xF0 & numbers[i]) ) |
---|
317 | { // foreground |
---|
318 | uint8 num = numbers[i]&0x0F; |
---|
319 | if(num==9) info.wAttributes |= FOREGROUND_INTENSITY; |
---|
320 | if(num>7) num=7; // set white for 37, 38 and 39 |
---|
321 | info.wAttributes &= ~(FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE); |
---|
322 | if( (num & 0x01)>0 ) // lowest bit set = red |
---|
323 | info.wAttributes |= FOREGROUND_RED; |
---|
324 | if( (num & 0x02)>0 ) // second bit set = green |
---|
325 | info.wAttributes |= FOREGROUND_GREEN; |
---|
326 | if( (num & 0x04)>0 ) // third bit set = blue |
---|
327 | info.wAttributes |= FOREGROUND_BLUE; |
---|
328 | } |
---|
329 | else if( 0x40 == (0xF0 & numbers[i]) ) |
---|
330 | { // background |
---|
331 | uint8 num = numbers[i]&0x0F; |
---|
332 | if(num==9) info.wAttributes |= BACKGROUND_INTENSITY; |
---|
333 | if(num>7) num=7; // set white for 47, 48 and 49 |
---|
334 | info.wAttributes &= ~(BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE); |
---|
335 | if( (num & 0x01)>0 ) // lowest bit set = red |
---|
336 | info.wAttributes |= BACKGROUND_RED; |
---|
337 | if( (num & 0x02)>0 ) // second bit set = green |
---|
338 | info.wAttributes |= BACKGROUND_GREEN; |
---|
339 | if( (num & 0x04)>0 ) // third bit set = blue |
---|
340 | info.wAttributes |= BACKGROUND_BLUE; |
---|
341 | } |
---|
342 | } |
---|
343 | // set the attributes |
---|
344 | SetConsoleTextAttribute(handle, info.wAttributes); |
---|
345 | } |
---|
346 | else if( *q=='J' ) |
---|
347 | { // \033[#J - Erase Display (ED) |
---|
348 | // \033[0J - Clears the screen from cursor to end of display. The cursor position is unchanged. |
---|
349 | // \033[1J - Clears the screen from start to cursor. The cursor position is unchanged. |
---|
350 | // \033[2J - Clears the screen and moves the cursor to the home position (line 1, column 1). |
---|
351 | uint8 num = (numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F); |
---|
352 | int cnt; |
---|
353 | DWORD tmp; |
---|
354 | COORD origin = {0,0}; |
---|
355 | if(num==1) |
---|
356 | { // chars from start up to and including cursor |
---|
357 | cnt = info.dwSize.X * info.dwCursorPosition.Y + info.dwCursorPosition.X + 1; |
---|
358 | } |
---|
359 | else if(num==2) |
---|
360 | { // Number of chars on screen. |
---|
361 | cnt = info.dwSize.X * info.dwSize.Y; |
---|
362 | SetConsoleCursorPosition(handle, origin); |
---|
363 | } |
---|
364 | else// 0 and default |
---|
365 | { // number of chars from cursor to end |
---|
366 | origin = info.dwCursorPosition; |
---|
367 | cnt = info.dwSize.X * (info.dwSize.Y - info.dwCursorPosition.Y) - info.dwCursorPosition.X; |
---|
368 | } |
---|
369 | FillConsoleOutputAttribute(handle, info.wAttributes, cnt, origin, &tmp); |
---|
370 | FillConsoleOutputCharacter(handle, ' ', cnt, origin, &tmp); |
---|
371 | } |
---|
372 | else if( *q=='K' ) |
---|
373 | { // \033[K : clear line from actual position to end of the line |
---|
374 | // \033[0K - Clears all characters from the cursor position to the end of the line. |
---|
375 | // \033[1K - Clears all characters from start of line to the cursor position. |
---|
376 | // \033[2K - Clears all characters of the whole line. |
---|
377 | |
---|
378 | uint8 num = (numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F); |
---|
379 | COORD origin = {0,info.dwCursorPosition.Y}; //warning C4204 |
---|
380 | SHORT cnt; |
---|
381 | DWORD tmp; |
---|
382 | if(num==1) |
---|
383 | { |
---|
384 | cnt = info.dwCursorPosition.X + 1; |
---|
385 | } |
---|
386 | else if(num==2) |
---|
387 | { |
---|
388 | cnt = info.dwSize.X; |
---|
389 | } |
---|
390 | else// 0 and default |
---|
391 | { |
---|
392 | origin = info.dwCursorPosition; |
---|
393 | cnt = info.dwSize.X - info.dwCursorPosition.X; // how many spaces until line is full |
---|
394 | } |
---|
395 | FillConsoleOutputAttribute(handle, info.wAttributes, cnt, origin, &tmp); |
---|
396 | FillConsoleOutputCharacter(handle, ' ', cnt, origin, &tmp); |
---|
397 | } |
---|
398 | else if( *q == 'H' || *q == 'f' ) |
---|
399 | { // \033[#;#H - Cursor Position (CUP) |
---|
400 | // \033[#;#f - Horizontal & Vertical Position |
---|
401 | // The first # specifies the line number, the second # specifies the column. |
---|
402 | // The default for both is 1 |
---|
403 | info.dwCursorPosition.X = (numbers[numpoint])?(numbers[numpoint]>>4)*10+((numbers[numpoint]&0x0F)-1):0; |
---|
404 | info.dwCursorPosition.Y = (numpoint && numbers[numpoint-1])?(numbers[numpoint-1]>>4)*10+((numbers[numpoint-1]&0x0F)-1):0; |
---|
405 | |
---|
406 | if( info.dwCursorPosition.X >= info.dwSize.X ) info.dwCursorPosition.Y = info.dwSize.X-1; |
---|
407 | if( info.dwCursorPosition.Y >= info.dwSize.Y ) info.dwCursorPosition.Y = info.dwSize.Y-1; |
---|
408 | SetConsoleCursorPosition(handle, info.dwCursorPosition); |
---|
409 | } |
---|
410 | else if( *q=='s' ) |
---|
411 | { // \033[s - Save Cursor Position (SCP) |
---|
412 | /* XXX Two streams are being used. Disabled to avoid inconsistency [flaviojs] |
---|
413 | CONSOLE_SCREEN_BUFFER_INFO info; |
---|
414 | GetConsoleScreenBufferInfo(handle, &info); |
---|
415 | saveposition = info.dwCursorPosition; |
---|
416 | */ |
---|
417 | } |
---|
418 | else if( *q=='u' ) |
---|
419 | { // \033[u - Restore cursor position (RCP) |
---|
420 | /* XXX Two streams are being used. Disabled to avoid inconsistency [flaviojs] |
---|
421 | SetConsoleCursorPosition(handle, saveposition); |
---|
422 | */ |
---|
423 | } |
---|
424 | else if( *q == 'A' ) |
---|
425 | { // \033[#A - Cursor Up (CUU) |
---|
426 | // Moves the cursor UP # number of lines |
---|
427 | info.dwCursorPosition.Y -= (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; |
---|
428 | |
---|
429 | if( info.dwCursorPosition.Y < 0 ) |
---|
430 | info.dwCursorPosition.Y = 0; |
---|
431 | SetConsoleCursorPosition(handle, info.dwCursorPosition); |
---|
432 | } |
---|
433 | else if( *q == 'B' ) |
---|
434 | { // \033[#B - Cursor Down (CUD) |
---|
435 | // Moves the cursor DOWN # number of lines |
---|
436 | info.dwCursorPosition.Y += (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; |
---|
437 | |
---|
438 | if( info.dwCursorPosition.Y >= info.dwSize.Y ) |
---|
439 | info.dwCursorPosition.Y = info.dwSize.Y-1; |
---|
440 | SetConsoleCursorPosition(handle, info.dwCursorPosition); |
---|
441 | } |
---|
442 | else if( *q == 'C' ) |
---|
443 | { // \033[#C - Cursor Forward (CUF) |
---|
444 | // Moves the cursor RIGHT # number of columns |
---|
445 | info.dwCursorPosition.X += (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; |
---|
446 | |
---|
447 | if( info.dwCursorPosition.X >= info.dwSize.X ) |
---|
448 | info.dwCursorPosition.X = info.dwSize.X-1; |
---|
449 | SetConsoleCursorPosition(handle, info.dwCursorPosition); |
---|
450 | } |
---|
451 | else if( *q == 'D' ) |
---|
452 | { // \033[#D - Cursor Backward (CUB) |
---|
453 | // Moves the cursor LEFT # number of columns |
---|
454 | info.dwCursorPosition.X -= (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; |
---|
455 | |
---|
456 | if( info.dwCursorPosition.X < 0 ) |
---|
457 | info.dwCursorPosition.X = 0; |
---|
458 | SetConsoleCursorPosition(handle, info.dwCursorPosition); |
---|
459 | } |
---|
460 | else if( *q == 'E' ) |
---|
461 | { // \033[#E - Cursor Next Line (CNL) |
---|
462 | // Moves the cursor down the indicated # of rows, to column 1 |
---|
463 | info.dwCursorPosition.Y += (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; |
---|
464 | info.dwCursorPosition.X = 0; |
---|
465 | |
---|
466 | if( info.dwCursorPosition.Y >= info.dwSize.Y ) |
---|
467 | info.dwCursorPosition.Y = info.dwSize.Y-1; |
---|
468 | SetConsoleCursorPosition(handle, info.dwCursorPosition); |
---|
469 | } |
---|
470 | else if( *q == 'F' ) |
---|
471 | { // \033[#F - Cursor Preceding Line (CPL) |
---|
472 | // Moves the cursor up the indicated # of rows, to column 1. |
---|
473 | info.dwCursorPosition.Y -= (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; |
---|
474 | info.dwCursorPosition.X = 0; |
---|
475 | |
---|
476 | if( info.dwCursorPosition.Y < 0 ) |
---|
477 | info.dwCursorPosition.Y = 0; |
---|
478 | SetConsoleCursorPosition(handle, info.dwCursorPosition); |
---|
479 | } |
---|
480 | else if( *q == 'G' ) |
---|
481 | { // \033[#G - Cursor Horizontal Absolute (CHA) |
---|
482 | // Moves the cursor to indicated column in current row. |
---|
483 | info.dwCursorPosition.X = (numbers[numpoint])?(numbers[numpoint]>>4)*10+((numbers[numpoint]&0x0F)-1):0; |
---|
484 | |
---|
485 | if( info.dwCursorPosition.X >= info.dwSize.X ) |
---|
486 | info.dwCursorPosition.X = info.dwSize.X-1; |
---|
487 | SetConsoleCursorPosition(handle, info.dwCursorPosition); |
---|
488 | } |
---|
489 | else if( *q == 'L' || *q == 'M' || *q == '@' || *q == 'P') |
---|
490 | { // not implemented, just skip |
---|
491 | } |
---|
492 | else |
---|
493 | { // no number nor valid sequencer |
---|
494 | // something is fishy, we break and give the current char free |
---|
495 | --q; |
---|
496 | } |
---|
497 | // skip the sequencer and search again |
---|
498 | p = q+1; |
---|
499 | break; |
---|
500 | }// end while |
---|
501 | } |
---|
502 | } |
---|
503 | if (*p) // write the rest of the buffer |
---|
504 | if( 0==WriteConsole(handle, p, (DWORD)strlen(p), &written, 0) ) |
---|
505 | WriteFile(handle, p, (DWORD)strlen(p), &written, 0); |
---|
506 | FREEBUF(tempbuf); |
---|
507 | return 0; |
---|
508 | } |
---|
509 | |
---|
510 | int FPRINTF(HANDLE handle, const char *fmt, ...) |
---|
511 | { |
---|
512 | int ret; |
---|
513 | va_list argptr; |
---|
514 | va_start(argptr, fmt); |
---|
515 | ret = VFPRINTF(handle,fmt,argptr); |
---|
516 | va_end(argptr); |
---|
517 | return ret; |
---|
518 | } |
---|
519 | |
---|
520 | #define FFLUSH(handle) |
---|
521 | |
---|
522 | #define STDOUT GetStdHandle(STD_OUTPUT_HANDLE) |
---|
523 | #define STDERR GetStdHandle(STD_ERROR_HANDLE) |
---|
524 | |
---|
525 | #else // not _WIN32 |
---|
526 | |
---|
527 | |
---|
528 | #define is_console(file) (0!=isatty(fileno(file))) |
---|
529 | |
---|
530 | //vprintf_without_ansiformats |
---|
531 | int VFPRINTF(FILE *file, const char *fmt, va_list argptr) |
---|
532 | { |
---|
533 | char *p, *q; |
---|
534 | NEWBUF(tempbuf); // temporary buffer |
---|
535 | |
---|
536 | if(!fmt || !*fmt) |
---|
537 | return 0; |
---|
538 | |
---|
539 | if( is_console(file) || stdout_with_ansisequence ) |
---|
540 | { |
---|
541 | vfprintf(file, fmt, argptr); |
---|
542 | return 0; |
---|
543 | } |
---|
544 | |
---|
545 | // Print everything to the buffer |
---|
546 | BUFVPRINTF(tempbuf,fmt,argptr); |
---|
547 | |
---|
548 | // start with processing |
---|
549 | p = BUFVAL(tempbuf); |
---|
550 | while ((q = strchr(p, 0x1b)) != NULL) |
---|
551 | { // find the escape character |
---|
552 | fprintf(file, "%.*s", (int)(q-p), p); // write up to the escape |
---|
553 | if( q[1]!='[' ) |
---|
554 | { // write the escape char (whatever purpose it has) |
---|
555 | fprintf(file, "%.*s", 1, q); |
---|
556 | p=q+1; //and start searching again |
---|
557 | } |
---|
558 | else |
---|
559 | { // from here, we will skip the '\033[' |
---|
560 | // we break at the first unprocessible position |
---|
561 | // assuming regular text is starting there |
---|
562 | |
---|
563 | // skip escape and bracket |
---|
564 | q=q+2; |
---|
565 | while(1) |
---|
566 | { |
---|
567 | if( ISDIGIT(*q) ) |
---|
568 | { |
---|
569 | ++q; |
---|
570 | // and next character |
---|
571 | continue; |
---|
572 | } |
---|
573 | else if( *q == ';' ) |
---|
574 | { // delimiter |
---|
575 | ++q; |
---|
576 | // and next number |
---|
577 | continue; |
---|
578 | } |
---|
579 | else if( *q == 'm' ) |
---|
580 | { // \033[#;...;#m - Set Graphics Rendition (SGR) |
---|
581 | // set the attributes |
---|
582 | } |
---|
583 | else if( *q=='J' ) |
---|
584 | { // \033[#J - Erase Display (ED) |
---|
585 | } |
---|
586 | else if( *q=='K' ) |
---|
587 | { // \033[K : clear line from actual position to end of the line |
---|
588 | } |
---|
589 | else if( *q == 'H' || *q == 'f' ) |
---|
590 | { // \033[#;#H - Cursor Position (CUP) |
---|
591 | // \033[#;#f - Horizontal & Vertical Position |
---|
592 | } |
---|
593 | else if( *q=='s' ) |
---|
594 | { // \033[s - Save Cursor Position (SCP) |
---|
595 | } |
---|
596 | else if( *q=='u' ) |
---|
597 | { // \033[u - Restore cursor position (RCP) |
---|
598 | } |
---|
599 | else if( *q == 'A' ) |
---|
600 | { // \033[#A - Cursor Up (CUU) |
---|
601 | // Moves the cursor UP # number of lines |
---|
602 | } |
---|
603 | else if( *q == 'B' ) |
---|
604 | { // \033[#B - Cursor Down (CUD) |
---|
605 | // Moves the cursor DOWN # number of lines |
---|
606 | } |
---|
607 | else if( *q == 'C' ) |
---|
608 | { // \033[#C - Cursor Forward (CUF) |
---|
609 | // Moves the cursor RIGHT # number of columns |
---|
610 | } |
---|
611 | else if( *q == 'D' ) |
---|
612 | { // \033[#D - Cursor Backward (CUB) |
---|
613 | // Moves the cursor LEFT # number of columns |
---|
614 | } |
---|
615 | else if( *q == 'E' ) |
---|
616 | { // \033[#E - Cursor Next Line (CNL) |
---|
617 | // Moves the cursor down the indicated # of rows, to column 1 |
---|
618 | } |
---|
619 | else if( *q == 'F' ) |
---|
620 | { // \033[#F - Cursor Preceding Line (CPL) |
---|
621 | // Moves the cursor up the indicated # of rows, to column 1. |
---|
622 | } |
---|
623 | else if( *q == 'G' ) |
---|
624 | { // \033[#G - Cursor Horizontal Absolute (CHA) |
---|
625 | // Moves the cursor to indicated column in current row. |
---|
626 | } |
---|
627 | else if( *q == 'L' || *q == 'M' || *q == '@' || *q == 'P') |
---|
628 | { // not implemented, just skip |
---|
629 | } |
---|
630 | else |
---|
631 | { // no number nor valid sequencer |
---|
632 | // something is fishy, we break and give the current char free |
---|
633 | --q; |
---|
634 | } |
---|
635 | // skip the sequencer and search again |
---|
636 | p = q+1; |
---|
637 | break; |
---|
638 | }// end while |
---|
639 | } |
---|
640 | } |
---|
641 | if (*p) // write the rest of the buffer |
---|
642 | fprintf(file, "%s", p); |
---|
643 | FREEBUF(tempbuf); |
---|
644 | return 0; |
---|
645 | } |
---|
646 | int FPRINTF(FILE *file, const char *fmt, ...) |
---|
647 | { |
---|
648 | int ret; |
---|
649 | va_list argptr; |
---|
650 | va_start(argptr, fmt); |
---|
651 | ret = VFPRINTF(file,fmt,argptr); |
---|
652 | va_end(argptr); |
---|
653 | return ret; |
---|
654 | } |
---|
655 | |
---|
656 | #define FFLUSH fflush |
---|
657 | |
---|
658 | #define STDOUT stdout |
---|
659 | #define STDERR stderr |
---|
660 | |
---|
661 | #endif// not _WIN32 |
---|
662 | |
---|
663 | |
---|
664 | |
---|
665 | |
---|
666 | |
---|
667 | |
---|
668 | |
---|
669 | |
---|
670 | |
---|
671 | |
---|
672 | char timestamp_format[20] = ""; //For displaying Timestamps |
---|
673 | |
---|
674 | int _vShowMessage(enum msg_type flag, const char *string, va_list ap) |
---|
675 | { |
---|
676 | char prefix[100]; |
---|
677 | #if defined(DEBUGLOGMAP) || defined(DEBUGLOGCHAR) || defined(DEBUGLOGLOGIN) |
---|
678 | FILE *fp; |
---|
679 | #endif |
---|
680 | |
---|
681 | if (!string || *string == '\0') { |
---|
682 | ShowError("Empty string passed to _vShowMessage().\n"); |
---|
683 | return 1; |
---|
684 | } |
---|
685 | if( |
---|
686 | (flag == MSG_INFORMATION && msg_silent&1) || |
---|
687 | (flag == MSG_STATUS && msg_silent&2) || |
---|
688 | (flag == MSG_NOTICE && msg_silent&4) || |
---|
689 | (flag == MSG_WARNING && msg_silent&8) || |
---|
690 | (flag == MSG_ERROR && msg_silent&16) || |
---|
691 | (flag == MSG_SQL && msg_silent&16) || |
---|
692 | (flag == MSG_DEBUG && msg_silent&32) |
---|
693 | ) |
---|
694 | return 0; //Do not print it. |
---|
695 | |
---|
696 | if (timestamp_format[0] && flag != MSG_NONE) |
---|
697 | { //Display time format. [Skotlex] |
---|
698 | time_t t = time(NULL); |
---|
699 | strftime(prefix, 80, timestamp_format, localtime(&t)); |
---|
700 | } else prefix[0]='\0'; |
---|
701 | |
---|
702 | switch (flag) { |
---|
703 | case MSG_NONE: // direct printf replacement |
---|
704 | break; |
---|
705 | case MSG_STATUS: //Bright Green (To inform about good things) |
---|
706 | strcat(prefix,CL_GREEN"[Status]"CL_RESET":"); |
---|
707 | break; |
---|
708 | case MSG_SQL: //Bright Violet (For dumping out anything related with SQL) <- Actually, this is mostly used for SQL errors with the database, as successes can as well just be anything else... [Skotlex] |
---|
709 | strcat(prefix,CL_MAGENTA"[SQL]"CL_RESET":"); |
---|
710 | break; |
---|
711 | case MSG_INFORMATION: //Bright White (Variable information) |
---|
712 | strcat(prefix,CL_WHITE"[Info]"CL_RESET":"); |
---|
713 | break; |
---|
714 | case MSG_NOTICE: //Bright White (Less than a warning) |
---|
715 | strcat(prefix,CL_WHITE"[Notice]"CL_RESET":"); |
---|
716 | break; |
---|
717 | case MSG_WARNING: //Bright Yellow |
---|
718 | strcat(prefix,CL_YELLOW"[Warning]"CL_RESET":"); |
---|
719 | break; |
---|
720 | case MSG_DEBUG: //Bright Cyan, important stuff! |
---|
721 | strcat(prefix,CL_CYAN"[Debug]"CL_RESET":"); |
---|
722 | break; |
---|
723 | case MSG_ERROR: //Bright Red (Regular errors) |
---|
724 | strcat(prefix,CL_RED"[Error]"CL_RESET":"); |
---|
725 | break; |
---|
726 | case MSG_FATALERROR: //Bright Red (Fatal errors, abort(); if possible) |
---|
727 | strcat(prefix,CL_RED"[Fatal Error]"CL_RESET":"); |
---|
728 | break; |
---|
729 | default: |
---|
730 | ShowError("In function _vShowMessage() -> Invalid flag passed.\n"); |
---|
731 | return 1; |
---|
732 | } |
---|
733 | |
---|
734 | if (flag == MSG_ERROR || flag == MSG_FATALERROR || flag == MSG_SQL) |
---|
735 | { //Send Errors to StdErr [Skotlex] |
---|
736 | FPRINTF(STDERR, "%s ", prefix); |
---|
737 | VFPRINTF(STDERR, string, ap); |
---|
738 | FFLUSH(STDERR); |
---|
739 | } else { |
---|
740 | if (flag != MSG_NONE) |
---|
741 | FPRINTF(STDOUT, "%s ", prefix); |
---|
742 | VFPRINTF(STDOUT, string, ap); |
---|
743 | FFLUSH(STDOUT); |
---|
744 | } |
---|
745 | |
---|
746 | #if defined(DEBUGLOGMAP) || defined(DEBUGLOGCHAR) || defined(DEBUGLOGLOGIN) |
---|
747 | if(strlen(DEBUGLOGPATH) > 0) { |
---|
748 | fp=fopen(DEBUGLOGPATH,"a"); |
---|
749 | if (fp == NULL) { |
---|
750 | FPRINTF(STDERR, CL_RED"[ERROR]"CL_RESET": Could not open '"CL_WHITE"%s"CL_RESET"', access denied.\n", DEBUGLOGPATH); |
---|
751 | FFLUSH(STDERR); |
---|
752 | } else { |
---|
753 | fprintf(fp,"%s ", prefix); |
---|
754 | vfprintf(fp,string,ap); |
---|
755 | fclose(fp); |
---|
756 | } |
---|
757 | } else { |
---|
758 | FPRINTF(STDERR, CL_RED"[ERROR]"CL_RESET": DEBUGLOGPATH not defined!\n"); |
---|
759 | FFLUSH(STDERR); |
---|
760 | } |
---|
761 | #endif |
---|
762 | |
---|
763 | va_end(ap); |
---|
764 | return 0; |
---|
765 | } |
---|
766 | |
---|
767 | void ClearScreen(void) |
---|
768 | { |
---|
769 | #ifndef _WIN32 |
---|
770 | ShowMessage(CL_CLS); // to prevent empty string passed messages |
---|
771 | #endif |
---|
772 | } |
---|
773 | int _ShowMessage(enum msg_type flag, const char *string, ...) |
---|
774 | { |
---|
775 | int ret; |
---|
776 | va_list ap; |
---|
777 | va_start(ap, string); |
---|
778 | ret = _vShowMessage(flag, string, ap); |
---|
779 | va_end(ap); |
---|
780 | return ret; |
---|
781 | } |
---|
782 | |
---|
783 | // direct printf replacement |
---|
784 | int ShowMessage(const char *string, ...) { |
---|
785 | int ret; |
---|
786 | va_list ap; |
---|
787 | va_start(ap, string); |
---|
788 | ret = _vShowMessage(MSG_NONE, string, ap); |
---|
789 | va_end(ap); |
---|
790 | return ret; |
---|
791 | } |
---|
792 | int ShowStatus(const char *string, ...) { |
---|
793 | int ret; |
---|
794 | va_list ap; |
---|
795 | va_start(ap, string); |
---|
796 | ret = _vShowMessage(MSG_STATUS, string, ap); |
---|
797 | va_end(ap); |
---|
798 | return ret; |
---|
799 | } |
---|
800 | int ShowSQL(const char *string, ...) { |
---|
801 | int ret; |
---|
802 | va_list ap; |
---|
803 | va_start(ap, string); |
---|
804 | ret = _vShowMessage(MSG_SQL, string, ap); |
---|
805 | va_end(ap); |
---|
806 | return ret; |
---|
807 | } |
---|
808 | int ShowInfo(const char *string, ...) { |
---|
809 | int ret; |
---|
810 | va_list ap; |
---|
811 | va_start(ap, string); |
---|
812 | ret = _vShowMessage(MSG_INFORMATION, string, ap); |
---|
813 | va_end(ap); |
---|
814 | return ret; |
---|
815 | } |
---|
816 | int ShowNotice(const char *string, ...) { |
---|
817 | int ret; |
---|
818 | va_list ap; |
---|
819 | va_start(ap, string); |
---|
820 | ret = _vShowMessage(MSG_NOTICE, string, ap); |
---|
821 | va_end(ap); |
---|
822 | return ret; |
---|
823 | } |
---|
824 | int ShowWarning(const char *string, ...) { |
---|
825 | int ret; |
---|
826 | va_list ap; |
---|
827 | va_start(ap, string); |
---|
828 | ret = _vShowMessage(MSG_WARNING, string, ap); |
---|
829 | va_end(ap); |
---|
830 | return ret; |
---|
831 | } |
---|
832 | int ShowDebug(const char *string, ...) { |
---|
833 | int ret; |
---|
834 | va_list ap; |
---|
835 | va_start(ap, string); |
---|
836 | ret = _vShowMessage(MSG_DEBUG, string, ap); |
---|
837 | va_end(ap); |
---|
838 | return ret; |
---|
839 | } |
---|
840 | int ShowError(const char *string, ...) { |
---|
841 | int ret; |
---|
842 | va_list ap; |
---|
843 | va_start(ap, string); |
---|
844 | ret = _vShowMessage(MSG_ERROR, string, ap); |
---|
845 | va_end(ap); |
---|
846 | return ret; |
---|
847 | } |
---|
848 | int ShowFatalError(const char *string, ...) { |
---|
849 | int ret; |
---|
850 | va_list ap; |
---|
851 | va_start(ap, string); |
---|
852 | ret = _vShowMessage(MSG_FATALERROR, string, ap); |
---|
853 | va_end(ap); |
---|
854 | return ret; |
---|
855 | } |
---|