[1] | 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 | } |
---|