root/src/common/showmsg.c @ 1

Revision 1, 27.9 kB (checked in by jinshiro, 17 years ago)
Line 
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
50int stdout_with_ansisequence = 0;
51
52int 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/*
176not implemented
177
178\033[#L
179IL: 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
181DL: 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[#\@
183ICH: 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
185DCH: 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
187Escape sequences for Select Character Set
188*/
189
190#define is_console(handle) (FILE_TYPE_CHAR==GetFileType(handle))
191
192///////////////////////////////////////////////////////////////////////////////
193int     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
510int     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
531int     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}
646int     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
672char timestamp_format[20] = ""; //For displaying Timestamps
673
674int _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
767void ClearScreen(void)
768{
769#ifndef _WIN32
770        ShowMessage(CL_CLS);    // to prevent empty string passed messages
771#endif
772}
773int _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
784int 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}
792int 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}
800int 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}
808int 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}
816int 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}
824int 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}
832int 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}
840int 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}
848int 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}
Note: See TracBrowser for help on using the browser.