showmsg.c 27 KB

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