/** * This file is part of Hercules. * http://herc.ws - http://github.com/HerculesWS/Hercules * * Copyright (C) 2012-2018 Hercules Dev Team * Copyright (C) Athena Dev Teams * * Hercules is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #define HERCULES_CORE #include "showmsg.h" #include "common/cbasetypes.h" #include "common/conf.h" #include "common/core.h" //[Ind] - For SERVER_TYPE #include "common/strlib.h" // StringBuf #include #include #include // atexit #ifdef WIN32 # include "common/winapi.h" #else // not WIN32 # include #endif // WIN32 #if defined(DEBUGLOGMAP) #define DEBUGLOGPATH "log"PATHSEP_STR"map-server.log" #elif defined(DEBUGLOGCHAR) #define DEBUGLOGPATH "log"PATHSEP_STR"char-server.log" #elif defined(DEBUGLOGLOGIN) #define DEBUGLOGPATH "log"PATHSEP_STR"login-server.log" #endif static struct showmsg_interface showmsg_s; struct showmsg_interface *showmsg; /////////////////////////////////////////////////////////////////////////////// /// static/dynamic buffer for the messages #define SBUF_SIZE 2054 // never put less that what's required for the debug message #define NEWBUF(buf) \ struct { \ char s_[SBUF_SIZE]; \ StringBuf *d_; \ char *v_; \ int l_; \ } buf ={"",NULL,NULL,0}; \ //define NEWBUF #define BUFVPRINTF(buf,fmt,args) do { \ (buf).l_ = vsnprintf((buf).s_, SBUF_SIZE, (fmt), args); \ if( (buf).l_ >= 0 && (buf).l_ < SBUF_SIZE ) \ {/* static buffer */ \ (buf).v_ = (buf).s_; \ } \ else \ {/* dynamic buffer */ \ (buf).d_ = StrBuf->Malloc(); \ (buf).l_ = StrBuf->Vprintf((buf).d_, (fmt), args); \ (buf).v_ = StrBuf->Value((buf).d_); \ ShowDebug("showmsg: dynamic buffer used, increase the static buffer size to %d or more.\n", (buf).l_+1); \ } \ } while(0) //define BUFVPRINTF #define BUFVAL(buf) ((buf).v_) #define BUFLEN(buf) ((buf).l_) #define FREEBUF(buf) do {\ if( (buf).d_ ) { \ StrBuf->Free((buf).d_); \ (buf).d_ = NULL; \ } \ (buf).v_ = NULL; \ } while(0) //define FREEBUF /////////////////////////////////////////////////////////////////////////////// #ifdef _WIN32 // XXX adapted from eApp (comments are left untouched) [flaviojs] /////////////////////////////////////////////////////////////////////////////// // ANSI compatible printf with control sequence parser for windows // fast hack, handle with care, not everything implemented // // \033[#;...;#m - Set Graphics Rendition (SGR) // // printf("\x1b[1;31;40m"); // Bright red on black // printf("\x1b[3;33;45m"); // Blinking yellow on magenta (blink not implemented) // printf("\x1b[1;30;47m"); // Bright black (grey) on dim white // // Style Foreground Background // 1st Digit 2nd Digit 3rd Digit RGB // 0 - Reset 30 - Black 40 - Black 000 // 1 - FG Bright 31 - Red 41 - Red 100 // 2 - Unknown 32 - Green 42 - Green 010 // 3 - Blink 33 - Yellow 43 - Yellow 110 // 4 - Underline 34 - Blue 44 - Blue 001 // 5 - BG Bright 35 - Magenta 45 - Magenta 101 // 6 - Unknown 36 - Cyan 46 - Cyan 011 // 7 - Reverse 37 - White 47 - White 111 // 8 - Concealed (invisible) // // \033[#A - Cursor Up (CUU) // Moves the cursor up by the specified number of lines without changing columns. // If the cursor is already on the top line, this sequence is ignored. \e[A is equivalent to \e[1A. // // \033[#B - Cursor Down (CUD) // Moves the cursor down by the specified number of lines without changing columns. // If the cursor is already on the bottom line, this sequence is ignored. \e[B is equivalent to \e[1B. // // \033[#C - Cursor Forward (CUF) // Moves the cursor forward by the specified number of columns without changing lines. // If the cursor is already in the rightmost column, this sequence is ignored. \e[C is equivalent to \e[1C. // // \033[#D - Cursor Backward (CUB) // Moves the cursor back by the specified number of columns without changing lines. // If the cursor is already in the leftmost column, this sequence is ignored. \e[D is equivalent to \e[1D. // // \033[#E - Cursor Next Line (CNL) // Moves the cursor down the indicated # of rows, to column 1. \e[E is equivalent to \e[1E. // // \033[#F - Cursor Preceding Line (CPL) // Moves the cursor up the indicated # of rows, to column 1. \e[F is equivalent to \e[1F. // // \033[#G - Cursor Horizontal Absolute (CHA) // Moves the cursor to indicated column in current row. \e[G is equivalent to \e[1G. // // \033[#;#H - Cursor Position (CUP) // Moves the cursor to the specified position. The first # specifies the line number, // the second # specifies the column. If you do not specify a position, the cursor moves to the home position: // the upper-left corner of the screen (line 1, column 1). // // \033[#;#f - Horizontal & Vertical Position // (same as \033[#;#H) // // \033[s - Save Cursor Position (SCP) // The current cursor position is saved. // // \033[u - Restore cursor position (RCP) // Restores the cursor position saved with the (SCP) sequence \033[s. // (addition, restore to 0,0 if nothing was saved before) // // \033[#J - Erase Display (ED) // Clears the screen and moves to the home position // \033[0J - Clears the screen from cursor to end of display. The cursor position is unchanged. (default) // \033[1J - Clears the screen from start to cursor. The cursor position is unchanged. // \033[2J - Clears the screen and moves the cursor to the home position (line 1, column 1). // // \033[#K - Erase Line (EL) // Clears the current line from the cursor position // \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) // \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. // \033[2K - Clears all characters of the whole line. The cursor position is unchanged. /* not implemented \033[#L 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. \033[#M 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. \033[#\@ 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\@. \033[#P 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. Escape sequences for Select Character Set */ #define is_console(handle) (FILE_TYPE_CHAR==GetFileType(handle)) /////////////////////////////////////////////////////////////////////////////// static int VFPRINTF(HANDLE handle, const char *fmt, va_list argptr) { ///////////////////////////////////////////////////////////////// /* XXX Two streams are being used. Disabled to avoid inconsistency [flaviojs] static COORD saveposition = {0,0}; */ ///////////////////////////////////////////////////////////////// DWORD written; char *p, *q; NEWBUF(tempbuf); // temporary buffer if(!fmt || !*fmt) return 0; // Print everything to the buffer BUFVPRINTF(tempbuf,fmt,argptr); if (!is_console(handle) && showmsg->stdout_with_ansisequence) { WriteFile(handle, BUFVAL(tempbuf), BUFLEN(tempbuf), &written, 0); return 0; } // start with processing p = BUFVAL(tempbuf); while ((q = strchr(p, 0x1b)) != NULL) { // find the escape character if( 0==WriteConsole(handle, p, (DWORD)(q-p), &written, 0) ) // write up to the escape WriteFile(handle, p, (DWORD)(q-p), &written, 0); if (q[1]!='[') { // write the escape char (whatever purpose it has) if(0==WriteConsole(handle, q, 1, &written, 0) ) WriteFile(handle,q, 1, &written, 0); p=q+1; //and start searching again } else { // from here, we will skip the '\033[' // we break at the first unprocessible position // assuming regular text is starting there uint8 numbers[16], numpoint=0; CONSOLE_SCREEN_BUFFER_INFO info; // initialize GetConsoleScreenBufferInfo(handle, &info); memset(numbers,0,sizeof(numbers)); // skip escape and bracket q=q+2; for (;;) { if (ISDIGIT(*q)) { // add number to number array, only accept 2digits, shift out the rest // so // \033[123456789m will become \033[89m numbers[numpoint] = (numbers[numpoint]<<4) | (*q-'0'); ++q; // and next character continue; } else if (*q == ';') { // delimiter if (numpoint < ARRAYLENGTH(numbers)) { // go to next array position numpoint++; } else { // array is full, so we 'forget' the first value memmove(numbers, numbers+1, ARRAYLENGTH(numbers)-1); numbers[ARRAYLENGTH(numbers)-1]=0; } ++q; // and next number continue; } else if (*q == 'm') { // \033[#;...;#m - Set Graphics Rendition (SGR) uint8 i; for (i=0; i<= numpoint; ++i) { if (0x00 == (0xF0 & numbers[i])) { // upper nibble 0 if (0 == numbers[i]) { // reset info.wAttributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; } else if (1 == numbers[i]) { // set foreground intensity info.wAttributes |= FOREGROUND_INTENSITY; } else if (5 == numbers[i]) { // set background intensity info.wAttributes |= BACKGROUND_INTENSITY; } else if (7 == numbers[i]) { // reverse colors (just xor them) info.wAttributes ^= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE; } //case '2': // not existing //case '3': // blinking (not implemented) //case '4': // underline (not implemented) //case '6': // not existing //case '8': // concealed (not implemented) //case '9': // not existing } else if (0x20 == (0xF0 & numbers[i])) { // off if (1 == numbers[i]) { // set foreground intensity off info.wAttributes &= ~FOREGROUND_INTENSITY; } else if (5 == numbers[i]) { // set background intensity off info.wAttributes &= ~BACKGROUND_INTENSITY; } else if (7 == numbers[i]) { // reverse colors (just xor them) info.wAttributes ^= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE; } } else if (0x30 == (0xF0 & numbers[i])) { // foreground uint8 num = numbers[i]&0x0F; if(num==9) info.wAttributes |= FOREGROUND_INTENSITY; if(num>7) num=7; // set white for 37, 38 and 39 info.wAttributes &= ~(FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE); if( (num & 0x01)>0 ) // lowest bit set = red info.wAttributes |= FOREGROUND_RED; if( (num & 0x02)>0 ) // second bit set = green info.wAttributes |= FOREGROUND_GREEN; if( (num & 0x04)>0 ) // third bit set = blue info.wAttributes |= FOREGROUND_BLUE; } else if (0x40 == (0xF0 & numbers[i])) { // background uint8 num = numbers[i]&0x0F; if(num==9) info.wAttributes |= BACKGROUND_INTENSITY; if(num>7) num=7; // set white for 47, 48 and 49 info.wAttributes &= ~(BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE); if( (num & 0x01)>0 ) // lowest bit set = red info.wAttributes |= BACKGROUND_RED; if( (num & 0x02)>0 ) // second bit set = green info.wAttributes |= BACKGROUND_GREEN; if( (num & 0x04)>0 ) // third bit set = blue info.wAttributes |= BACKGROUND_BLUE; } } // set the attributes SetConsoleTextAttribute(handle, info.wAttributes); } else if (*q=='J') { // \033[#J - Erase Display (ED) // \033[0J - Clears the screen from cursor to end of display. The cursor position is unchanged. // \033[1J - Clears the screen from start to cursor. The cursor position is unchanged. // \033[2J - Clears the screen and moves the cursor to the home position (line 1, column 1). uint8 num = (numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F); int cnt; DWORD tmp; COORD origin = {0,0}; if (num == 1) { // chars from start up to and including cursor cnt = info.dwSize.X * info.dwCursorPosition.Y + info.dwCursorPosition.X + 1; } else if (num == 2) { // Number of chars on screen. cnt = info.dwSize.X * info.dwSize.Y; SetConsoleCursorPosition(handle, origin); } else { /* 0 and default */ // number of chars from cursor to end origin = info.dwCursorPosition; cnt = info.dwSize.X * (info.dwSize.Y - info.dwCursorPosition.Y) - info.dwCursorPosition.X; } FillConsoleOutputAttribute(handle, info.wAttributes, cnt, origin, &tmp); FillConsoleOutputCharacter(handle, ' ', cnt, origin, &tmp); } else if (*q=='K') { // \033[K : clear line from actual position to end of the line // \033[0K - Clears all characters from the cursor position to the end of the line. // \033[1K - Clears all characters from start of line to the cursor position. // \033[2K - Clears all characters of the whole line. uint8 num = (numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F); COORD origin = {0,info.dwCursorPosition.Y}; //warning C4204 SHORT cnt; DWORD tmp; if (num == 1) { cnt = info.dwCursorPosition.X + 1; } else if (num == 2) { cnt = info.dwSize.X; } else { /* 0 and default */ origin = info.dwCursorPosition; cnt = info.dwSize.X - info.dwCursorPosition.X; // how many spaces until line is full } FillConsoleOutputAttribute(handle, info.wAttributes, cnt, origin, &tmp); FillConsoleOutputCharacter(handle, ' ', cnt, origin, &tmp); } else if (*q == 'H' || *q == 'f') { // \033[#;#H - Cursor Position (CUP) // \033[#;#f - Horizontal & Vertical Position // The first # specifies the line number, the second # specifies the column. // The default for both is 1 info.dwCursorPosition.X = (numbers[numpoint])?(numbers[numpoint]>>4)*10+((numbers[numpoint]&0x0F)-1):0; info.dwCursorPosition.Y = (numpoint && numbers[numpoint-1])?(numbers[numpoint-1]>>4)*10+((numbers[numpoint-1]&0x0F)-1):0; if( info.dwCursorPosition.X >= info.dwSize.X ) info.dwCursorPosition.Y = info.dwSize.X-1; if( info.dwCursorPosition.Y >= info.dwSize.Y ) info.dwCursorPosition.Y = info.dwSize.Y-1; SetConsoleCursorPosition(handle, info.dwCursorPosition); } else if (*q=='s') { // \033[s - Save Cursor Position (SCP) /* XXX Two streams are being used. Disabled to avoid inconsistency [flaviojs] CONSOLE_SCREEN_BUFFER_INFO info; GetConsoleScreenBufferInfo(handle, &info); saveposition = info.dwCursorPosition; */ } else if (*q=='u') { // \033[u - Restore cursor position (RCP) /* XXX Two streams are being used. Disabled to avoid inconsistency [flaviojs] SetConsoleCursorPosition(handle, saveposition); */ } else if (*q == 'A') { // \033[#A - Cursor Up (CUU) // Moves the cursor UP # number of lines info.dwCursorPosition.Y -= (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; if( info.dwCursorPosition.Y < 0 ) info.dwCursorPosition.Y = 0; SetConsoleCursorPosition(handle, info.dwCursorPosition); } else if (*q == 'B') { // \033[#B - Cursor Down (CUD) // Moves the cursor DOWN # number of lines info.dwCursorPosition.Y += (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; if( info.dwCursorPosition.Y >= info.dwSize.Y ) info.dwCursorPosition.Y = info.dwSize.Y-1; SetConsoleCursorPosition(handle, info.dwCursorPosition); } else if (*q == 'C') { // \033[#C - Cursor Forward (CUF) // Moves the cursor RIGHT # number of columns info.dwCursorPosition.X += (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; if( info.dwCursorPosition.X >= info.dwSize.X ) info.dwCursorPosition.X = info.dwSize.X-1; SetConsoleCursorPosition(handle, info.dwCursorPosition); } else if (*q == 'D') { // \033[#D - Cursor Backward (CUB) // Moves the cursor LEFT # number of columns info.dwCursorPosition.X -= (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; if( info.dwCursorPosition.X < 0 ) info.dwCursorPosition.X = 0; SetConsoleCursorPosition(handle, info.dwCursorPosition); } else if (*q == 'E') { // \033[#E - Cursor Next Line (CNL) // Moves the cursor down the indicated # of rows, to column 1 info.dwCursorPosition.Y += (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; info.dwCursorPosition.X = 0; if( info.dwCursorPosition.Y >= info.dwSize.Y ) info.dwCursorPosition.Y = info.dwSize.Y-1; SetConsoleCursorPosition(handle, info.dwCursorPosition); } else if (*q == 'F') { // \033[#F - Cursor Preceding Line (CPL) // Moves the cursor up the indicated # of rows, to column 1. info.dwCursorPosition.Y -= (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; info.dwCursorPosition.X = 0; if( info.dwCursorPosition.Y < 0 ) info.dwCursorPosition.Y = 0; SetConsoleCursorPosition(handle, info.dwCursorPosition); } else if (*q == 'G') { // \033[#G - Cursor Horizontal Absolute (CHA) // Moves the cursor to indicated column in current row. info.dwCursorPosition.X = (numbers[numpoint])?(numbers[numpoint]>>4)*10+((numbers[numpoint]&0x0F)-1):0; if( info.dwCursorPosition.X >= info.dwSize.X ) info.dwCursorPosition.X = info.dwSize.X-1; SetConsoleCursorPosition(handle, info.dwCursorPosition); } else if (*q == 'L' || *q == 'M' || *q == '@' || *q == 'P') { // not implemented, just skip } else { // no number nor valid sequencer // something is fishy, we break and give the current char free --q; } // skip the sequencer and search again p = q+1; break; }// end while } } if (*p) // write the rest of the buffer if( 0==WriteConsole(handle, p, (DWORD)strlen(p), &written, 0) ) WriteFile(handle, p, (DWORD)strlen(p), &written, 0); FREEBUF(tempbuf); return 0; } static int FPRINTF(HANDLE handle, const char *fmt, ...) __attribute__((format(printf, 2, 3))); static int FPRINTF(HANDLE handle, const char *fmt, ...) { int ret; va_list argptr; va_start(argptr, fmt); ret = VFPRINTF(handle,fmt,argptr); va_end(argptr); return ret; } #define FFLUSH(handle) (void)(handle) #define STDOUT GetStdHandle(STD_OUTPUT_HANDLE) #define STDERR GetStdHandle(STD_ERROR_HANDLE) #else // not _WIN32 #define is_console(file) (0!=isatty(fileno(file))) //vprintf_without_ansiformats static int VFPRINTF(FILE *file, const char *fmt, va_list argptr) { char *p, *q; NEWBUF(tempbuf); // temporary buffer if(!fmt || !*fmt) return 0; if (is_console(file) || showmsg->stdout_with_ansisequence) { vfprintf(file, fmt, argptr); return 0; } // Print everything to the buffer BUFVPRINTF(tempbuf,fmt,argptr); // start with processing p = BUFVAL(tempbuf); while ((q = strchr(p, 0x1b)) != NULL) { // find the escape character fprintf(file, "%.*s", (int)(q-p), p); // write up to the escape if (q[1]!='[') { // write the escape char (whatever purpose it has) fprintf(file, "%.*s", 1, q); p=q+1; //and start searching again } else { // from here, we will skip the '\033[' // we break at the first unprocessible position // assuming regular text is starting there // skip escape and bracket q=q+2; while(1) { if (ISDIGIT(*q)) { ++q; // and next character continue; } else if (*q == ';') { // delimiter ++q; // and next number continue; } else if (*q == 'm') { // \033[#;...;#m - Set Graphics Rendition (SGR) // set the attributes } else if (*q=='J') { // \033[#J - Erase Display (ED) } else if (*q=='K') { // \033[K : clear line from actual position to end of the line } else if (*q == 'H' || *q == 'f') { // \033[#;#H - Cursor Position (CUP) // \033[#;#f - Horizontal & Vertical Position } else if (*q=='s') { // \033[s - Save Cursor Position (SCP) } else if (*q=='u') { // \033[u - Restore cursor position (RCP) } else if (*q == 'A') { // \033[#A - Cursor Up (CUU) // Moves the cursor UP # number of lines } else if (*q == 'B') { // \033[#B - Cursor Down (CUD) // Moves the cursor DOWN # number of lines } else if (*q == 'C') { // \033[#C - Cursor Forward (CUF) // Moves the cursor RIGHT # number of columns } else if (*q == 'D') { // \033[#D - Cursor Backward (CUB) // Moves the cursor LEFT # number of columns } else if (*q == 'E') { // \033[#E - Cursor Next Line (CNL) // Moves the cursor down the indicated # of rows, to column 1 } else if (*q == 'F') { // \033[#F - Cursor Preceding Line (CPL) // Moves the cursor up the indicated # of rows, to column 1. } else if (*q == 'G') { // \033[#G - Cursor Horizontal Absolute (CHA) // Moves the cursor to indicated column in current row. } else if (*q == 'L' || *q == 'M' || *q == '@' || *q == 'P') { // not implemented, just skip } else { // no number nor valid sequencer // something is fishy, we break and give the current char free --q; } // skip the sequencer and search again p = q+1; break; }// end while } } if (*p) // write the rest of the buffer fprintf(file, "%s", p); FREEBUF(tempbuf); return 0; } static int FPRINTF(FILE *file, const char *fmt, ...) __attribute__((format(printf, 2, 3))); static int FPRINTF(FILE *file, const char *fmt, ...) { int ret; va_list argptr; va_start(argptr, fmt); ret = VFPRINTF(file,fmt,argptr); va_end(argptr); return ret; } #define FFLUSH fflush #define STDOUT stdout #define STDERR stderr #endif// not _WIN32 static int vShowMessage_(enum msg_type flag, const char *string, va_list ap) { va_list apcopy; char prefix[100]; if (!string || *string == '\0') { ShowError("Empty string passed to vShowMessage_().\n"); return 1; } if( ( flag == MSG_WARNING && showmsg->console_log&1 ) || ( ( flag == MSG_ERROR || flag == MSG_SQL ) && showmsg->console_log&2 ) || ( flag == MSG_DEBUG && showmsg->console_log&4 ) ) {//[Ind] FILE *log = NULL; if( (log = fopen(SERVER_TYPE == SERVER_TYPE_MAP ? "./log/map-msg_log.log" : "./log/unknown.log","a+")) ) { char timestring[255]; time_t curtime; time(&curtime); strftime(timestring, 254, "%m/%d/%Y %H:%M:%S", localtime(&curtime)); fprintf(log,"(%s) [ %s ] : ", timestring, flag == MSG_WARNING ? "Warning" : flag == MSG_ERROR ? "Error" : flag == MSG_SQL ? "SQL Error" : flag == MSG_DEBUG ? "Debug" : "Unknown"); va_copy(apcopy, ap); vfprintf(log,string,apcopy); va_end(apcopy); fclose(log); } } if( (flag == MSG_INFORMATION && showmsg->silent&1) || (flag == MSG_STATUS && showmsg->silent&2) || (flag == MSG_NOTICE && showmsg->silent&4) || (flag == MSG_WARNING && showmsg->silent&8) || (flag == MSG_ERROR && showmsg->silent&16) || (flag == MSG_SQL && showmsg->silent&16) || (flag == MSG_DEBUG && showmsg->silent&32) ) return 0; //Do not print it. if (showmsg->timestamp_format[0] && flag != MSG_NONE) { //Display time format. [Skotlex] time_t t = time(NULL); strftime(prefix, 80, showmsg->timestamp_format, localtime(&t)); } else prefix[0]='\0'; switch (flag) { case MSG_NONE: // direct printf replacement break; case MSG_STATUS: //Bright Green (To inform about good things) strcat(prefix,CL_GREEN"[Status]"CL_RESET":"); break; 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] strcat(prefix,CL_MAGENTA"[SQL]"CL_RESET":"); break; case MSG_INFORMATION: //Bright White (Variable information) strcat(prefix,CL_WHITE"[Info]"CL_RESET":"); break; case MSG_NOTICE: //Bright White (Less than a warning) strcat(prefix,CL_WHITE"[Notice]"CL_RESET":"); break; case MSG_WARNING: //Bright Yellow strcat(prefix,CL_YELLOW"[Warning]"CL_RESET":"); break; case MSG_DEBUG: //Bright Cyan, important stuff! strcat(prefix,CL_CYAN"[Debug]"CL_RESET":"); break; case MSG_ERROR: //Bright Red (Regular errors) strcat(prefix,CL_RED"[Error]"CL_RESET":"); break; case MSG_FATALERROR: //Bright Red (Fatal errors, abort(); if possible) strcat(prefix,CL_RED"[Fatal Error]"CL_RESET":"); break; default: ShowError("In function vShowMessage_() -> Invalid flag passed.\n"); return 1; } if (flag == MSG_ERROR || flag == MSG_FATALERROR || flag == MSG_SQL) { //Send Errors to StdErr [Skotlex] FPRINTF(STDERR, "%s ", prefix); va_copy(apcopy, ap); VFPRINTF(STDERR, string, apcopy); va_end(apcopy); FFLUSH(STDERR); } else { if (flag != MSG_NONE) FPRINTF(STDOUT, "%s ", prefix); va_copy(apcopy, ap); VFPRINTF(STDOUT, string, apcopy); va_end(apcopy); FFLUSH(STDOUT); } #if defined(DEBUGLOGMAP) || defined(DEBUGLOGCHAR) || defined(DEBUGLOGLOGIN) if (strlen(DEBUGLOGPATH) > 0) { FILE *fp = fopen(DEBUGLOGPATH,"a"); if (fp == NULL) { FPRINTF(STDERR, CL_RED"[ERROR]"CL_RESET": Could not open '"CL_WHITE"%s"CL_RESET"', access denied.\n", DEBUGLOGPATH); FFLUSH(STDERR); } else { fprintf(fp,"%s ", prefix); va_copy(apcopy, ap); vfprintf(fp,string,apcopy); va_end(apcopy); fclose(fp); } } else { FPRINTF(STDERR, CL_RED"[ERROR]"CL_RESET": DEBUGLOGPATH not defined!\n"); FFLUSH(STDERR); } #endif return 0; } static int showmsg_vShowMessage(const char *string, va_list ap) { int ret; va_list apcopy; va_copy(apcopy, ap); ret = vShowMessage_(MSG_NONE, string, apcopy); va_end(apcopy); return ret; } static void showmsg_clearScreen(void) { #ifndef _WIN32 ShowMessage(CL_CLS); // to prevent empty string passed messages #endif } #if 0 // Unused static int ShowMessage_(enum msg_type flag, const char *string, ...) __attribute__((format(printf, 2, 3))); static int ShowMessage_(enum msg_type flag, const char *string, ...) { int ret; va_list ap; va_start(ap, string); ret = vShowMessage_(flag, string, ap); va_end(ap); return ret; } #endif // Unused // direct printf replacement static void showmsg_showMessage(const char *string, ...) __attribute__((format(printf, 1, 2))); static void showmsg_showMessage(const char *string, ...) { va_list ap; va_start(ap, string); vShowMessage_(MSG_NONE, string, ap); va_end(ap); } static void showmsg_showStatus(const char *string, ...) __attribute__((format(printf, 1, 2))); static void showmsg_showStatus(const char *string, ...) { va_list ap; va_start(ap, string); vShowMessage_(MSG_STATUS, string, ap); va_end(ap); } static void showmsg_showSQL(const char *string, ...) __attribute__((format(printf, 1, 2))); static void showmsg_showSQL(const char *string, ...) { va_list ap; va_start(ap, string); vShowMessage_(MSG_SQL, string, ap); va_end(ap); } static void showmsg_showInfo(const char *string, ...) __attribute__((format(printf, 1, 2))); static void showmsg_showInfo(const char *string, ...) { va_list ap; va_start(ap, string); vShowMessage_(MSG_INFORMATION, string, ap); va_end(ap); } static void showmsg_showNotice(const char *string, ...) __attribute__((format(printf, 1, 2))); static void showmsg_showNotice(const char *string, ...) { va_list ap; va_start(ap, string); vShowMessage_(MSG_NOTICE, string, ap); va_end(ap); } static void showmsg_showWarning(const char *string, ...) __attribute__((format(printf, 1, 2))); static void showmsg_showWarning(const char *string, ...) { va_list ap; va_start(ap, string); vShowMessage_(MSG_WARNING, string, ap); va_end(ap); } static void showmsg_showConfigWarning(struct config_setting_t *config, const char *string, ...) __attribute__((format(printf, 2, 3))); static void showmsg_showConfigWarning(struct config_setting_t *config, const char *string, ...) { StringBuf buf; va_list ap; StrBuf->Init(&buf); StrBuf->AppendStr(&buf, string); StrBuf->Printf(&buf, " (%s:%u)\n", config_setting_source_file(config), config_setting_source_line(config)); va_start(ap, string); #ifdef BUILDBOT vShowMessage_(MSG_ERROR, StrBuf->Value(&buf), ap); #else // BUILDBOT vShowMessage_(MSG_WARNING, StrBuf->Value(&buf), ap); #endif // BUILDBOT va_end(ap); StrBuf->Destroy(&buf); } static void showmsg_showDebug(const char *string, ...) __attribute__((format(printf, 1, 2))); static void showmsg_showDebug(const char *string, ...) { va_list ap; va_start(ap, string); vShowMessage_(MSG_DEBUG, string, ap); va_end(ap); } static void showmsg_showError(const char *string, ...) __attribute__((format(printf, 1, 2))); static void showmsg_showError(const char *string, ...) { va_list ap; va_start(ap, string); vShowMessage_(MSG_ERROR, string, ap); va_end(ap); } static void showmsg_showFatalError(const char *string, ...) __attribute__((format(printf, 1, 2))); static void showmsg_showFatalError(const char *string, ...) { va_list ap; va_start(ap, string); vShowMessage_(MSG_FATALERROR, string, ap); va_end(ap); } static void showmsg_init(void) { } static void showmsg_final(void) { } void showmsg_defaults(void) { showmsg = &showmsg_s; /////////////////////////////////////////////////////////////////////////////// /// behavioral parameter. /// when redirecting output: /// if true prints escape sequences /// if false removes the escape sequences showmsg->stdout_with_ansisequence = false; showmsg->silent = 0; //Specifies how silent the console is. showmsg->console_log = 0;//[Ind] msg error logging memset(showmsg->timestamp_format, '\0', sizeof(showmsg->timestamp_format)); showmsg->init = showmsg_init; showmsg->final = showmsg_final; showmsg->clearScreen = showmsg_clearScreen; showmsg->showMessageV = showmsg_vShowMessage; showmsg->showMessage = showmsg_showMessage; showmsg->showStatus = showmsg_showStatus; showmsg->showSQL = showmsg_showSQL; showmsg->showInfo = showmsg_showInfo; showmsg->showNotice = showmsg_showNotice; showmsg->showWarning = showmsg_showWarning; showmsg->showDebug = showmsg_showDebug; showmsg->showError = showmsg_showError; showmsg->showFatalError = showmsg_showFatalError; showmsg->showConfigWarning = showmsg_showConfigWarning; }