showmsg.cpp 28 KB

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