showmsg.c 29 KB

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