|
@@ -5,9 +5,14 @@
|
|
|
#include <string.h>
|
|
|
#include <stdarg.h>
|
|
|
#include <time.h>
|
|
|
+#include <stdlib.h> // atexit
|
|
|
+#include "../common/cbasetypes.h"
|
|
|
#include "showmsg.h"
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
+ #define WIN32_LEAN_AND_MEAN
|
|
|
+ #include <windows.h>
|
|
|
+
|
|
|
#ifdef DEBUGLOGMAP
|
|
|
#define DEBUGLOGPATH "log\\map-server.log"
|
|
|
#else
|
|
@@ -20,6 +25,9 @@
|
|
|
#endif
|
|
|
#endif
|
|
|
#else
|
|
|
+ #include <unistd.h>
|
|
|
+ #include <ctype.h>
|
|
|
+
|
|
|
#ifdef DEBUGLOGMAP
|
|
|
#define DEBUGLOGPATH "log/map-server.log"
|
|
|
#else
|
|
@@ -33,9 +41,605 @@
|
|
|
#endif
|
|
|
#endif
|
|
|
|
|
|
+///////////////////////////////////////////////////////////////////////////////
|
|
|
+/// behavioral parameter.
|
|
|
+/// when true, prints ansi sequences also when redirecting outputs to file
|
|
|
+/// otherwise remove them
|
|
|
+int stdout_with_ansisequence = 1;
|
|
|
+
|
|
|
int msg_silent; //Specifies how silent the console is.
|
|
|
-char tmp_output[1024] = {"\0"};
|
|
|
+
|
|
|
+///////////////////////////////////////////////////////////////////////////////
|
|
|
+/// small reallocating temporary printer buffer
|
|
|
+static char *tempbuf = NULL;
|
|
|
+static size_t sz = 0;
|
|
|
+#define tempbuf_size() (sz)
|
|
|
+static void tempbuf_free(void){ free(tempbuf); }
|
|
|
+static void tempbuf_alloc(void){ sz = 256; tempbuf = (char *)malloc(sz); atexit(tempbuf_free); }
|
|
|
+static void tempbuf_realloc(void){ sz <<= 1; tempbuf = (char *)realloc(tempbuf,sz); }
|
|
|
+
|
|
|
+///////////////////////////////////////////////////////////////////////////////
|
|
|
+#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 nothinh 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))
|
|
|
+
|
|
|
+///////////////////////////////////////////////////////////////////////////////
|
|
|
+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};
|
|
|
+ */
|
|
|
+
|
|
|
+ /////////////////////////////////////////////////////////////////
|
|
|
+ unsigned long written;
|
|
|
+ char *p, *q;
|
|
|
+
|
|
|
+ if(!fmt || !*fmt)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ if(tempbuf == NULL)
|
|
|
+ tempbuf_alloc();
|
|
|
+ for(; vsnprintf(tempbuf, tempbuf_size(), fmt, argptr)<0; tempbuf_realloc());
|
|
|
+ // vsnprintf returns -1 in case of insufficient buffer size
|
|
|
+ // tempbuf_realloc doubles the size of the buffer in this case
|
|
|
+
|
|
|
+ if( !is_console(handle) && stdout_with_ansisequence )
|
|
|
+ {
|
|
|
+ WriteFile(handle,tempbuf, strlen(tempbuf), &written, 0);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ // start with processing
|
|
|
+ p = tempbuf;
|
|
|
+ while ((q = strchr(p, 0x1b)) != NULL)
|
|
|
+ { // find the escape character
|
|
|
+ if( 0==WriteConsole(handle, p, q-p, &written, 0) ) // write up to the escape
|
|
|
+ WriteFile(handle, p, 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
|
|
|
+ uchar 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;
|
|
|
+ while(1)
|
|
|
+ {
|
|
|
+ if( isdigit((int)((unsigned char)*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<sizeof(numbers)/sizeof(*numbers))
|
|
|
+ { // go to next array position
|
|
|
+ numpoint++;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ { // array is full, so we 'forget' the first value
|
|
|
+ memmove(numbers,numbers+1,sizeof(numbers)/sizeof(*numbers)-1);
|
|
|
+ numbers[sizeof(numbers)/sizeof(*numbers)-1]=0;
|
|
|
+ }
|
|
|
+ ++q;
|
|
|
+ // and next number
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ else if( *q == 'm' )
|
|
|
+ { // \033[#;...;#m - Set Graphics Rendition (SGR)
|
|
|
+ uint 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': // unterline (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
|
|
|
+ uint 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
|
|
|
+ uint 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).
|
|
|
+ uint num = (numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F);
|
|
|
+ int cnt;
|
|
|
+ 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,NULL);
|
|
|
+ FillConsoleOutputCharacter(handle,' ', cnt,origin,NULL);
|
|
|
+ }
|
|
|
+ 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.
|
|
|
+
|
|
|
+ uint num = (numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F);
|
|
|
+ COORD origin = {0,info.dwCursorPosition.Y};
|
|
|
+ SHORT cnt;
|
|
|
+ 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, NULL);
|
|
|
+ FillConsoleOutputCharacter(handle, ' ', cnt, origin, NULL);
|
|
|
+ }
|
|
|
+ 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, strlen(p), &written, 0) )
|
|
|
+ WriteFile(handle,p, strlen(p), &written, 0);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+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)
|
|
|
+
|
|
|
+#define STDOUT GetStdHandle(STD_OUTPUT_HANDLE)
|
|
|
+#define STDERR GetStdHandle(STD_ERROR_HANDLE)
|
|
|
+
|
|
|
+#else // not _WIN32
|
|
|
+
|
|
|
+
|
|
|
+//#define VPRINTF vprintf
|
|
|
+//#define PRINTF printf
|
|
|
+
|
|
|
+#define is_console(file) (0!=isatty(fileno(file)))
|
|
|
+
|
|
|
+//vprintf_without_ansiformats
|
|
|
+int VFPRINTF(FILE *file, const char *fmt, va_list argptr)
|
|
|
+{
|
|
|
+ char *p, *q;
|
|
|
+
|
|
|
+ if(!fmt || !*fmt)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ if( is_console(file) || stdout_with_ansisequence )
|
|
|
+ {
|
|
|
+ vfprintf(file, fmt, argptr);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(tempbuf == NULL)
|
|
|
+ tempbuf_alloc();
|
|
|
+ for(; vsnprintf(tempbuf, tempbuf_size(), fmt, argptr)<0; tempbuf_realloc());
|
|
|
+ // vsnprintf returns -1 in case of insufficient buffer size
|
|
|
+ // tempbuf.realloc doubles the size of the buffer in this case
|
|
|
+
|
|
|
+ // start with processing
|
|
|
+ p = 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((int)((unsigned char)*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);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+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
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
char timestamp_format[20] = ""; //For displaying Timestamps
|
|
|
+
|
|
|
// by MC Cameri
|
|
|
int _vShowMessage(enum msg_type flag, const char *string, va_list ap)
|
|
|
{
|
|
@@ -47,10 +651,18 @@ int _vShowMessage(enum msg_type flag, const char *string, va_list ap)
|
|
|
FILE *fp;
|
|
|
#endif
|
|
|
|
|
|
- if (!string || strlen(string) <= 0) {
|
|
|
+ if (!string || *string == '\0') {
|
|
|
ShowError("Empty string passed to _vShowMessage().\n");
|
|
|
return 1;
|
|
|
}
|
|
|
+ if ((flag == MSG_DEBUG && !SHOW_DEBUG_MSG) ||
|
|
|
+ (flag == MSG_INFORMATION && msg_silent&1) ||
|
|
|
+ (flag == MSG_STATUS && msg_silent&2) ||
|
|
|
+ (flag == MSG_NOTICE && msg_silent&4) ||
|
|
|
+ (flag == MSG_WARNING && msg_silent&8) ||
|
|
|
+ (flag == MSG_ERROR && msg_silent&16) ||
|
|
|
+ (flag == MSG_SQL && msg_silent&16))
|
|
|
+ return 0; //Do not print it.
|
|
|
|
|
|
if (timestamp_format[0])
|
|
|
{ //Display time format. [Skotlex]
|
|
@@ -58,7 +670,6 @@ int _vShowMessage(enum msg_type flag, const char *string, va_list ap)
|
|
|
strftime(prefix, 80, timestamp_format, localtime(&t));
|
|
|
} else prefix[0]='\0';
|
|
|
|
|
|
-
|
|
|
switch (flag) {
|
|
|
case MSG_NONE: // direct printf replacement
|
|
|
break;
|
|
@@ -91,60 +702,36 @@ int _vShowMessage(enum msg_type flag, const char *string, va_list ap)
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
- if ((flag == MSG_DEBUG && !SHOW_DEBUG_MSG) ||
|
|
|
- (flag == MSG_INFORMATION && msg_silent&1) ||
|
|
|
- (flag == MSG_STATUS && msg_silent&2) ||
|
|
|
- (flag == MSG_NOTICE && msg_silent&4) ||
|
|
|
- (flag == MSG_WARNING && msg_silent&8) ||
|
|
|
- (flag == MSG_ERROR && msg_silent&16) ||
|
|
|
- (flag == MSG_SQL && msg_silent&16)
|
|
|
- ) ; //Do not print it.
|
|
|
- else {
|
|
|
- if (flag == MSG_ERROR || flag == MSG_FATALERROR || flag == MSG_SQL)
|
|
|
- { //Send Errors to StdErr [Skotlex]
|
|
|
- fprintf (stderr, "%s ", prefix);
|
|
|
- vfprintf (stderr, string, ap);
|
|
|
- fflush (stderr);
|
|
|
- } else {
|
|
|
- if (flag != MSG_NONE)
|
|
|
- printf ("%s ", prefix);
|
|
|
- vprintf (string, ap);
|
|
|
- fflush (stdout);
|
|
|
- }
|
|
|
+ if (flag == MSG_ERROR || flag == MSG_FATALERROR || flag == MSG_SQL)
|
|
|
+ { //Send Errors to StdErr [Skotlex]
|
|
|
+ FPRINTF(STDERR, "%s ", prefix);
|
|
|
+ VFPRINTF(STDERR, string, ap);
|
|
|
+ FFLUSH(STDERR);
|
|
|
+ } else {
|
|
|
+ if (flag != MSG_NONE)
|
|
|
+ FPRINTF(STDOUT, "%s ", prefix);
|
|
|
+ VFPRINTF(STDOUT, string, ap);
|
|
|
+ FFLUSH(STDOUT);
|
|
|
}
|
|
|
|
|
|
#if defined(DEBUGLOGMAP) || defined(DEBUGLOGCHAR) || defined(DEBUGLOGLOGIN)
|
|
|
if(strlen(DEBUGLOGPATH) > 0) {
|
|
|
fp=fopen(DEBUGLOGPATH,"a");
|
|
|
if (fp == NULL) {
|
|
|
- printf(CL_RED"[ERROR]"CL_RESET": Could not open '"CL_WHITE"%s"CL_RESET"', access denied.\n",DEBUGLOGPATH);
|
|
|
- fflush(stdout);
|
|
|
- return 0;
|
|
|
+ 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);
|
|
|
+ vfprintf(fp,string,ap);
|
|
|
+ fclose(fp);
|
|
|
}
|
|
|
- fprintf(fp,"%s ", prefix);
|
|
|
- vfprintf(fp,string,ap);
|
|
|
- fclose(fp);
|
|
|
} else {
|
|
|
- printf(CL_RED"[ERROR]"CL_RESET": DEBUGLOGPATH not defined!\n");
|
|
|
+ FPRINTF(STDERR, CL_RED"[ERROR]"CL_RESET": DEBUGLOGPATH not defined!\n");
|
|
|
+ FFLUSH(STDERR);
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
va_end(ap);
|
|
|
-/*
|
|
|
- if ((core_config.debug_output_level > -1) && (flag >= core_config.debug_output_level)) {
|
|
|
- FILE *fp;
|
|
|
- fp=fopen(OUTPUT_MESSAGES_LOG,"a");
|
|
|
- if (fp == NULL) {
|
|
|
- ShowError("Could not open '"CL_WHITE"%s"CL_RESET"', file not found.\n",OUTPUT_MESSAGES_LOG);
|
|
|
- fflush(stdout);
|
|
|
- return;
|
|
|
- }
|
|
|
- StripColor(output);
|
|
|
- strcpy(output,"\r");
|
|
|
- fwrite(output,strlen(output),1,fp);
|
|
|
- fclose(fp);
|
|
|
- }
|
|
|
-*/
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -156,64 +743,84 @@ void ClearScreen(void)
|
|
|
}
|
|
|
int _ShowMessage(enum msg_type flag, const char *string, ...)
|
|
|
{
|
|
|
+ int ret;
|
|
|
va_list ap;
|
|
|
-
|
|
|
va_start(ap, string);
|
|
|
- return _vShowMessage(flag, string, ap);
|
|
|
+ ret = _vShowMessage(flag, string, ap);
|
|
|
+ va_end(ap);
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
// direct printf replacement
|
|
|
int ShowMessage(const char *string, ...) {
|
|
|
+ int ret;
|
|
|
va_list ap;
|
|
|
-
|
|
|
va_start(ap, string);
|
|
|
- return _vShowMessage(MSG_NONE, string, ap);
|
|
|
+ ret = _vShowMessage(MSG_NONE, string, ap);
|
|
|
+ va_end(ap);
|
|
|
+ return ret;
|
|
|
}
|
|
|
int ShowStatus(const char *string, ...) {
|
|
|
+ int ret;
|
|
|
va_list ap;
|
|
|
-
|
|
|
va_start(ap, string);
|
|
|
- return _vShowMessage(MSG_STATUS, string, ap);
|
|
|
+ ret = _vShowMessage(MSG_STATUS, string, ap);
|
|
|
+ va_end(ap);
|
|
|
+ return ret;
|
|
|
}
|
|
|
int ShowSQL(const char *string, ...) {
|
|
|
+ int ret;
|
|
|
va_list ap;
|
|
|
-
|
|
|
va_start(ap, string);
|
|
|
- return _vShowMessage(MSG_SQL, string, ap);
|
|
|
+ ret = _vShowMessage(MSG_SQL, string, ap);
|
|
|
+ va_end(ap);
|
|
|
+ return ret;
|
|
|
}
|
|
|
int ShowInfo(const char *string, ...) {
|
|
|
+ int ret;
|
|
|
va_list ap;
|
|
|
-
|
|
|
va_start(ap, string);
|
|
|
- return _vShowMessage(MSG_INFORMATION, string, ap);
|
|
|
+ ret = _vShowMessage(MSG_INFORMATION, string, ap);
|
|
|
+ va_end(ap);
|
|
|
+ return ret;
|
|
|
}
|
|
|
int ShowNotice(const char *string, ...) {
|
|
|
+ int ret;
|
|
|
va_list ap;
|
|
|
-
|
|
|
va_start(ap, string);
|
|
|
- return _vShowMessage(MSG_NOTICE, string, ap);
|
|
|
+ ret = _vShowMessage(MSG_NOTICE, string, ap);
|
|
|
+ va_end(ap);
|
|
|
+ return ret;
|
|
|
}
|
|
|
int ShowWarning(const char *string, ...) {
|
|
|
+ int ret;
|
|
|
va_list ap;
|
|
|
-
|
|
|
va_start(ap, string);
|
|
|
- return _vShowMessage(MSG_WARNING, string, ap);
|
|
|
+ ret = _vShowMessage(MSG_WARNING, string, ap);
|
|
|
+ va_end(ap);
|
|
|
+ return ret;
|
|
|
}
|
|
|
int ShowDebug(const char *string, ...) {
|
|
|
+ int ret;
|
|
|
va_list ap;
|
|
|
-
|
|
|
va_start(ap, string);
|
|
|
- return _vShowMessage(MSG_DEBUG, string, ap);
|
|
|
+ ret = _vShowMessage(MSG_DEBUG, string, ap);
|
|
|
+ va_end(ap);
|
|
|
+ return ret;
|
|
|
}
|
|
|
-int ShowError(const char *string, ...) {
|
|
|
+int ShowError(const char *string, ...) {
|
|
|
+ int ret;
|
|
|
va_list ap;
|
|
|
-
|
|
|
va_start(ap, string);
|
|
|
- return _vShowMessage(MSG_ERROR, string, ap);
|
|
|
+ ret = _vShowMessage(MSG_ERROR, string, ap);
|
|
|
+ va_end(ap);
|
|
|
+ return ret;
|
|
|
}
|
|
|
int ShowFatalError(const char *string, ...) {
|
|
|
+ int ret;
|
|
|
va_list ap;
|
|
|
-
|
|
|
va_start(ap, string);
|
|
|
- return _vShowMessage(MSG_FATALERROR, string, ap);
|
|
|
+ ret = _vShowMessage(MSG_FATALERROR, string, ap);
|
|
|
+ va_end(ap);
|
|
|
+ return ret;
|
|
|
}
|