showmsg.c 28 KB

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