strlib.cpp 27 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097
  1. // Copyright (c) rAthena Dev Teams - Licensed under GNU GPL
  2. // For more information, see LICENCE in the main folder
  3. #include "strlib.hpp"
  4. #include <algorithm>
  5. #include <cstdlib>
  6. #include "cbasetypes.hpp"
  7. #include "malloc.hpp"
  8. #include "showmsg.hpp"
  9. // Function to suppress control characters in a string.
  10. int32 remove_control_chars(char* str)
  11. {
  12. int32 i;
  13. int32 change = 0;
  14. for(i = 0; str[i]; i++) {
  15. if (ISCNTRL(str[i])) {
  16. str[i] = '_';
  17. change = 1;
  18. }
  19. }
  20. return change;
  21. }
  22. // Removes characters identified by ISSPACE from the start and end of the string
  23. // NOTE: make sure the string is not const!!
  24. char* trim(char* str)
  25. {
  26. size_t start;
  27. size_t end;
  28. if( str == nullptr )
  29. return str;
  30. // get start position
  31. for( start = 0; str[start] && ISSPACE(str[start]); ++start )
  32. ;
  33. // get end position
  34. for( end = strlen(str); start < end && str[end-1] && ISSPACE(str[end-1]); --end )
  35. ;
  36. // trim
  37. if( start == end )
  38. *str = '\0';// empty string
  39. else
  40. {// move string with nul terminator
  41. str[end] = '\0';
  42. memmove(str,str+start,end-start+1);
  43. }
  44. return str;
  45. }
  46. // Converts one or more consecutive occurences of the delimiters into a single space
  47. // and removes such occurences from the beginning and end of string
  48. // NOTE: make sure the string is not const!!
  49. char* normalize_name(char* str,const char* delims)
  50. {
  51. char* in = str;
  52. char* out = str;
  53. int32 put_space = 0;
  54. if( str == nullptr || delims == nullptr )
  55. return str;
  56. // trim start of string
  57. while( *in && strchr(delims,*in) )
  58. ++in;
  59. while( *in )
  60. {
  61. if( put_space )
  62. {// replace trim characters with a single space
  63. *out = ' ';
  64. ++out;
  65. }
  66. // copy non trim characters
  67. while( *in && !strchr(delims,*in) )
  68. {
  69. *out = *in;
  70. ++out;
  71. ++in;
  72. }
  73. // skip trim characters
  74. while( *in && strchr(delims,*in) )
  75. ++in;
  76. put_space = 1;
  77. }
  78. *out = '\0';
  79. return str;
  80. }
  81. //stristr: Case insensitive version of strstr, code taken from
  82. //http://www.daniweb.com/code/snippet313.html, Dave Sinkula
  83. //
  84. const char* stristr(const char* haystack, const char* needle)
  85. {
  86. if ( !*needle )
  87. {
  88. return haystack;
  89. }
  90. for ( ; *haystack; ++haystack )
  91. {
  92. if ( TOUPPER(*haystack) == TOUPPER(*needle) )
  93. {
  94. // matched starting char -- loop through remaining chars
  95. const char *h, *n;
  96. for ( h = haystack, n = needle; *h && *n; ++h, ++n )
  97. {
  98. if ( TOUPPER(*h) != TOUPPER(*n) )
  99. {
  100. break;
  101. }
  102. }
  103. if ( !*n ) // matched all of 'needle' to null termination
  104. {
  105. return haystack; // return the start of the match
  106. }
  107. }
  108. }
  109. return 0;
  110. }
  111. #ifdef __WIN32
  112. char* _strtok_r(char *s1, const char *s2, char **lasts)
  113. {
  114. char *ret;
  115. if (s1 == nullptr)
  116. s1 = *lasts;
  117. while(*s1 && strchr(s2, *s1))
  118. ++s1;
  119. if(*s1 == '\0')
  120. return nullptr;
  121. ret = s1;
  122. while(*s1 && !strchr(s2, *s1))
  123. ++s1;
  124. if(*s1)
  125. *s1++ = '\0';
  126. *lasts = s1;
  127. return ret;
  128. }
  129. #endif
  130. #if !(defined(WIN32) && defined(_MSC_VER) && _MSC_VER >= 1400) && !defined(HAVE_STRNLEN)
  131. /* Find the length of STRING, but scan at most MAXLEN characters.
  132. If no '\0' terminator is found in that many characters, return MAXLEN. */
  133. size_t strnlen (const char* string, size_t maxlen)
  134. {
  135. const char* end = (const char*)memchr(string, '\0', maxlen);
  136. return end ? (size_t) (end - string) : maxlen;
  137. }
  138. #endif
  139. #if defined(WIN32) && defined(_MSC_VER) && _MSC_VER <= 1200
  140. uint64 strtoull(const char* str, char** endptr, int32 base)
  141. {
  142. uint64 result;
  143. int32 count;
  144. int32 n;
  145. if( base == 0 )
  146. {
  147. if( str[0] == '0' && (str[1] == 'x' || str[1] == 'X') )
  148. base = 16;
  149. else
  150. if( str[0] == '0' )
  151. base = 8;
  152. else
  153. base = 10;
  154. }
  155. if( base == 8 )
  156. count = sscanf(str, "%I64o%n", &result, &n);
  157. else
  158. if( base == 10 )
  159. count = sscanf(str, "%I64u%n", &result, &n);
  160. else
  161. if( base == 16 )
  162. count = sscanf(str, "%I64x%n", &result, &n);
  163. else
  164. count = 0; // fail
  165. if( count < 1 )
  166. {
  167. errno = EINVAL;
  168. result = 0;
  169. n = 0;
  170. }
  171. if( endptr )
  172. *endptr = (char*)str + n;
  173. return result;
  174. }
  175. #endif
  176. //----------------------------------------------------
  177. // E-mail check: return 0 (not correct) or 1 (valid).
  178. //----------------------------------------------------
  179. int32 e_mail_check(char* email)
  180. {
  181. char ch;
  182. char* last_arobas;
  183. size_t len = strlen(email);
  184. // athena limits
  185. if (len < 3 || len > 39)
  186. return 0;
  187. // part of RFC limits (official reference of e-mail description)
  188. if (strchr(email, '@') == nullptr || email[len-1] == '@')
  189. return 0;
  190. if (email[len-1] == '.')
  191. return 0;
  192. last_arobas = strrchr(email, '@');
  193. if (strstr(last_arobas, "@.") != nullptr || strstr(last_arobas, "..") != nullptr)
  194. return 0;
  195. for(ch = 1; ch < 32; ch++)
  196. if (strchr(last_arobas, ch) != nullptr)
  197. return 0;
  198. if (strchr(last_arobas, ' ') != nullptr || strchr(last_arobas, ';') != nullptr)
  199. return 0;
  200. // all correct
  201. return 1;
  202. }
  203. //--------------------------------------------------
  204. // Return numerical value of a switch configuration
  205. // on/off, english, fran�ais, deutsch, espa�ol, portuguese
  206. //--------------------------------------------------
  207. int32 config_switch(const char* str)
  208. {
  209. if (strcmpi(str, "on") == 0 || strcmpi(str, "yes") == 0 || strcmpi(str, "oui") == 0 || strcmpi(str, "ja") == 0 || strcmpi(str, "si") == 0 || strcmpi(str, "sim") == 0)
  210. return 1;
  211. if (strcmpi(str, "off") == 0 || strcmpi(str, "no") == 0 || strcmpi(str, "non") == 0 || strcmpi(str, "nein") == 0 || strcmpi(str, "nao") == 0)
  212. return 0;
  213. return (int32)strtol(str, nullptr, 0);
  214. }
  215. /// strncpy that always nul-terminates the string
  216. char* safestrncpy(char* dst, const char* src, size_t n)
  217. {
  218. if( n > 0 )
  219. {
  220. char* d = dst;
  221. const char* s = src;
  222. d[--n] = '\0';/* nul-terminate string */
  223. for( ; n > 0; --n )
  224. {
  225. if( (*d++ = *s++) == '\0' )
  226. {/* nul-pad remaining bytes */
  227. while( --n > 0 )
  228. *d++ = '\0';
  229. break;
  230. }
  231. }
  232. }
  233. return dst;
  234. }
  235. /// doesn't crash on null pointer
  236. size_t safestrnlen(const char* string, size_t maxlen)
  237. {
  238. return ( string != nullptr ) ? strnlen(string, maxlen) : 0;
  239. }
  240. /// Works like snprintf, but always nul-terminates the buffer.
  241. /// Returns the size of the string (without nul-terminator)
  242. /// or -1 if the buffer is too small.
  243. ///
  244. /// @param buf Target buffer
  245. /// @param sz Size of the buffer (including nul-terminator)
  246. /// @param fmt Format string
  247. /// @param ... Format arguments
  248. /// @return The size of the string or -1 if the buffer is too small
  249. int32 safesnprintf(char* buf, size_t sz, const char* fmt, ...)
  250. {
  251. va_list ap;
  252. int32 ret;
  253. va_start(ap,fmt);
  254. ret = vsnprintf(buf, sz, fmt, ap);
  255. va_end(ap);
  256. if( ret < 0 || (size_t)ret >= sz )
  257. {// overflow
  258. buf[sz-1] = '\0';// always nul-terminate
  259. return -1;
  260. }
  261. return ret;
  262. }
  263. /// Returns the line of the target position in the string.
  264. /// Lines start at 1.
  265. int32 strline(const char* str, size_t pos)
  266. {
  267. const char* target;
  268. int32 line;
  269. if( str == nullptr || pos == 0 )
  270. return 1;
  271. target = str+pos;
  272. for( line = 1; ; ++line )
  273. {
  274. str = strchr(str, '\n');
  275. if( str == nullptr || target <= str )
  276. break;// found target line
  277. ++str;// skip newline
  278. }
  279. return line;
  280. }
  281. /// Produces the hexadecimal representation of the given input.
  282. /// The output buffer must be at least count*2+1 in size.
  283. /// Returns true on success, false on failure.
  284. ///
  285. /// @param output Output string
  286. /// @param input Binary input buffer
  287. /// @param count Number of bytes to convert
  288. bool bin2hex(char* output, unsigned char* input, size_t count)
  289. {
  290. char toHex[] = "0123456789abcdef";
  291. size_t i;
  292. for( i = 0; i < count; ++i )
  293. {
  294. *output++ = toHex[(*input & 0xF0) >> 4];
  295. *output++ = toHex[(*input & 0x0F) >> 0];
  296. ++input;
  297. }
  298. *output = '\0';
  299. return true;
  300. }
  301. /////////////////////////////////////////////////////////////////////
  302. /// Parses a single field in a delim-separated string.
  303. /// The delimiter after the field is skipped.
  304. ///
  305. /// @param sv Parse state
  306. /// @return 1 if a field was parsed, 0 if already done, -1 on error.
  307. int32 sv_parse_next( s_svstate& sv ){
  308. enum {
  309. START_OF_FIELD,
  310. PARSING_FIELD,
  311. PARSING_C_ESCAPE,
  312. END_OF_FIELD,
  313. TERMINATE,
  314. END
  315. } state;
  316. const char* str = sv.str;
  317. size_t len = sv.len;
  318. int32 opt = sv.opt;
  319. char delim = sv.delim;
  320. // check opt
  321. if( delim == '\n' && (opt&(SV_TERMINATE_CRLF|SV_TERMINATE_LF)) )
  322. {
  323. ShowError("sv_parse_next: delimiter '\\n' is not compatible with options SV_TERMINATE_LF or SV_TERMINATE_CRLF.\n");
  324. return -1;// error
  325. }
  326. if( delim == '\r' && (opt&(SV_TERMINATE_CRLF|SV_TERMINATE_CR)) )
  327. {
  328. ShowError("sv_parse_next: delimiter '\\r' is not compatible with options SV_TERMINATE_CR or SV_TERMINATE_CRLF.\n");
  329. return -1;// error
  330. }
  331. if( sv.done || str == nullptr )
  332. {
  333. sv.done = true;
  334. return 0;// nothing to parse
  335. }
  336. #define IS_END() ( i >= len )
  337. #define IS_DELIM() ( str[i] == delim )
  338. #define IS_TERMINATOR() ( \
  339. ((opt&SV_TERMINATE_LF) && str[i] == '\n') || \
  340. ((opt&SV_TERMINATE_CR) && str[i] == '\r') || \
  341. ((opt&SV_TERMINATE_CRLF) && i+1 < len && str[i] == '\r' && str[i+1] == '\n') )
  342. #define IS_C_ESCAPE() ( (opt&SV_ESCAPE_C) && str[i] == '\\' )
  343. #define SET_FIELD_START() sv.start = i
  344. #define SET_FIELD_END() sv.end = i
  345. size_t i = sv.off;
  346. state = START_OF_FIELD;
  347. while( state != END )
  348. {
  349. switch( state )
  350. {
  351. case START_OF_FIELD:// record start of field and start parsing it
  352. SET_FIELD_START();
  353. state = PARSING_FIELD;
  354. break;
  355. case PARSING_FIELD:// skip field character
  356. if( IS_END() || IS_DELIM() || IS_TERMINATOR() )
  357. state = END_OF_FIELD;
  358. else if( IS_C_ESCAPE() )
  359. state = PARSING_C_ESCAPE;
  360. else
  361. ++i;// normal character
  362. break;
  363. case PARSING_C_ESCAPE:// skip escape sequence (validates it too)
  364. {
  365. ++i;// '\\'
  366. if( IS_END() )
  367. {
  368. ShowError("sv_parse_next: empty escape sequence\n");
  369. return -1;
  370. }
  371. if( str[i] == 'x' )
  372. {// hex escape
  373. ++i;// 'x'
  374. if( IS_END() || !ISXDIGIT(str[i]) )
  375. {
  376. ShowError("sv_parse_next: \\x with no following hex digits\n");
  377. return -1;
  378. }
  379. do{
  380. ++i;// hex digit
  381. }while( !IS_END() && ISXDIGIT(str[i]));
  382. }
  383. else if( str[i] == '0' || str[i] == '1' || str[i] == '2' )
  384. {// octal escape
  385. ++i;// octal digit
  386. if( !IS_END() && str[i] >= '0' && str[i] <= '7' )
  387. ++i;// octal digit
  388. if( !IS_END() && str[i] >= '0' && str[i] <= '7' )
  389. ++i;// octal digit
  390. }
  391. else if( strchr(SV_ESCAPE_C_SUPPORTED, str[i]) )
  392. {// supported escape character
  393. ++i;
  394. }
  395. else
  396. {
  397. ShowError("sv_parse_next: unknown escape sequence \\%c\n", str[i]);
  398. return -1;
  399. }
  400. state = PARSING_FIELD;
  401. break;
  402. }
  403. case END_OF_FIELD:// record end of field and stop
  404. SET_FIELD_END();
  405. state = END;
  406. if( IS_END() )
  407. ;// nothing else
  408. else if( IS_DELIM() )
  409. ++i;// delim
  410. else if( IS_TERMINATOR() )
  411. state = TERMINATE;
  412. break;
  413. case TERMINATE:
  414. #if 0
  415. // skip line terminator
  416. if( (opt&SV_TERMINATE_CRLF) && i+1 < len && str[i] == '\r' && str[i+1] == '\n' )
  417. i += 2;// CRLF
  418. else
  419. ++i;// CR or LF
  420. #endif
  421. sv.done = true;
  422. state = END;
  423. break;
  424. }
  425. }
  426. if( IS_END() )
  427. sv.done = true;
  428. sv.off = i;
  429. #undef IS_END
  430. #undef IS_DELIM
  431. #undef IS_TERMINATOR
  432. #undef IS_C_ESCAPE
  433. #undef SET_FIELD_START
  434. #undef SET_FIELD_END
  435. return 1;
  436. }
  437. /// Parses a delim-separated string.
  438. /// Starts parsing at startoff and fills the pos array with position pairs.
  439. /// out_pos[0] and out_pos[1] are the start and end of line.
  440. /// Other position pairs are the start and end of fields.
  441. /// Returns the number of fields found or -1 if an error occurs.
  442. ///
  443. /// out_pos can be nullptr.
  444. /// If a line terminator is found, the end position is placed there.
  445. /// out_pos[2] and out_pos[3] for the first field, out_pos[4] and out_pos[5]
  446. /// for the seconds field and so on.
  447. /// Unfilled positions are set to -1.
  448. ///
  449. /// @param str String to parse
  450. /// @param len Length of the string
  451. /// @param startoff Where to start parsing
  452. /// @param delim Field delimiter
  453. /// @param out_pos Array of resulting positions
  454. /// @param npos Size of the pos array
  455. /// @param opt Options that determine the parsing behaviour
  456. /// @return Number of fields found in the string or -1 if an error occured
  457. size_t sv_parse( const char* str, size_t len, size_t startoff, char delim, size_t* out_pos, size_t npos, int32 opt, bool& error ){
  458. // initialize
  459. error = false;
  460. if( out_pos == nullptr ){
  461. npos = 0;
  462. }
  463. for( size_t i = 0; i < npos; ++i ){
  464. out_pos[i] = -1;
  465. }
  466. s_svstate sv = {};
  467. sv.str = str;
  468. sv.len = len;
  469. sv.off = startoff;
  470. sv.opt = opt;
  471. sv.delim = delim;
  472. sv.done = false;
  473. if( npos > 0 ){
  474. out_pos[0] = startoff;
  475. }
  476. // parse
  477. size_t count = 0;
  478. while( !sv.done ){
  479. ++count;
  480. if( sv_parse_next( sv ) <= 0 ){
  481. error = true;
  482. return 0;
  483. }
  484. if( npos > count * 2 ){
  485. out_pos[count * 2] = sv.start;
  486. }
  487. if( npos > count * 2 + 1 ){
  488. out_pos[count * 2 + 1] = sv.end;
  489. }
  490. }
  491. if( npos > 1 ){
  492. out_pos[1] = sv.off;
  493. }
  494. return count;
  495. }
  496. /// Splits a delim-separated string.
  497. /// WARNING: this function modifies the input string
  498. /// Starts splitting at startoff and fills the out_fields array.
  499. /// out_fields[0] is the start of the next line.
  500. /// Other entries are the start of fields (nul-teminated).
  501. /// Returns the number of fields found or -1 if an error occurs.
  502. ///
  503. /// out_fields can be nullptr.
  504. /// Fields that don't fit in out_fields are not nul-terminated.
  505. /// Extra entries in out_fields are filled with the end of the last field (empty string).
  506. ///
  507. /// @param str String to parse
  508. /// @param len Length of the string
  509. /// @param startoff Where to start parsing
  510. /// @param delim Field delimiter
  511. /// @param out_fields Array of resulting fields
  512. /// @param nfields Size of the field array
  513. /// @param opt Options that determine the parsing behaviour
  514. /// @return Number of fields found in the string or -1 if an error occured
  515. size_t sv_split( char* str, size_t len, size_t startoff, char delim, char** out_fields, size_t nfields, int32 opt, bool& error ){
  516. if( out_fields == nullptr || nfields <= 0 ){
  517. return 0; // nothing to do
  518. }
  519. size_t pos[1024];
  520. size_t ret = sv_parse( str, len, startoff, delim, pos, ARRAYLENGTH( pos ), opt, error );
  521. // An error occurred
  522. if( error ){
  523. return 0;
  524. }
  525. // next line
  526. char* end = str + pos[1];
  527. if( end[0] == '\0' )
  528. {
  529. *out_fields = end;
  530. }
  531. else if( (opt&SV_TERMINATE_LF) && end[0] == '\n' )
  532. {
  533. if( !(opt&SV_KEEP_TERMINATOR) )
  534. end[0] = '\0';
  535. *out_fields = end + 1;
  536. }
  537. else if( (opt&SV_TERMINATE_CRLF) && end[0] == '\r' && end[1] == '\n' )
  538. {
  539. if( !(opt&SV_KEEP_TERMINATOR) )
  540. end[0] = end[1] = '\0';
  541. *out_fields = end + 2;
  542. }
  543. else if( (opt&SV_TERMINATE_CR) && end[0] == '\r' )
  544. {
  545. if( !(opt&SV_KEEP_TERMINATOR) )
  546. end[0] = '\0';
  547. *out_fields = end + 1;
  548. }
  549. else
  550. {
  551. ShowError("sv_split: unknown line delimiter 0x02%x.\n", (unsigned char)end[0]);
  552. return -1;// error
  553. }
  554. ++out_fields;
  555. --nfields;
  556. // fields
  557. size_t i = 2;
  558. size_t done = 0;
  559. while( done < ret && nfields > 0 )
  560. {
  561. if( i < ARRAYLENGTH(pos) )
  562. {// split field
  563. *out_fields = str + pos[i];
  564. end = str + pos[i+1];
  565. *end = '\0';
  566. // next field
  567. i += 2;
  568. ++done;
  569. ++out_fields;
  570. --nfields;
  571. }
  572. else
  573. {// get more fields
  574. sv_parse( str, len, pos[i - 1] + 1, delim, pos, ARRAYLENGTH( pos ), opt, error );
  575. // An error occurred
  576. if( error ){
  577. return 0;
  578. }
  579. i = 2;
  580. }
  581. }
  582. // remaining fields
  583. for( i = 0; i < nfields; ++i )
  584. out_fields[i] = end;
  585. return ret;
  586. }
  587. /// Escapes src to out_dest according to the format of the C compiler.
  588. /// Returns the length of the escaped string.
  589. /// out_dest should be len*4+1 in size.
  590. ///
  591. /// @param out_dest Destination buffer
  592. /// @param src Source string
  593. /// @param len Length of the source string
  594. /// @param escapes Extra characters to be escaped
  595. /// @return Length of the escaped string
  596. size_t sv_escape_c(char* out_dest, const char* src, size_t len, const char* escapes)
  597. {
  598. size_t i;
  599. size_t j;
  600. if( out_dest == nullptr )
  601. return 0;// nothing to do
  602. if( src == nullptr )
  603. {// nothing to escape
  604. *out_dest = 0;
  605. return 0;
  606. }
  607. if( escapes == nullptr )
  608. escapes = "";
  609. for( i = 0, j = 0; i < len; ++i )
  610. {
  611. switch( src[i] )
  612. {
  613. case '\0':// octal 0
  614. out_dest[j++] = '\\';
  615. out_dest[j++] = '0';
  616. out_dest[j++] = '0';
  617. out_dest[j++] = '0';
  618. break;
  619. case '\r':// carriage return
  620. out_dest[j++] = '\\';
  621. out_dest[j++] = 'r';
  622. break;
  623. case '\n':// line feed
  624. out_dest[j++] = '\\';
  625. out_dest[j++] = 'n';
  626. break;
  627. case '\\':// escape character
  628. out_dest[j++] = '\\';
  629. out_dest[j++] = '\\';
  630. break;
  631. default:
  632. if( strchr(escapes,src[i]) )
  633. {// escape
  634. out_dest[j++] = '\\';
  635. switch( src[i] )
  636. {
  637. case '\a': out_dest[j++] = 'a'; break;
  638. case '\b': out_dest[j++] = 'b'; break;
  639. case '\t': out_dest[j++] = 't'; break;
  640. case '\v': out_dest[j++] = 'v'; break;
  641. case '\f': out_dest[j++] = 'f'; break;
  642. case '\?': out_dest[j++] = '?'; break;
  643. default:// to octal
  644. out_dest[j++] = '0'+((char)(((unsigned char)src[i]&0700)>>6));
  645. out_dest[j++] = '0'+((char)(((unsigned char)src[i]&0070)>>3));
  646. out_dest[j++] = '0'+((char)(((unsigned char)src[i]&0007) ));
  647. break;
  648. }
  649. }
  650. else
  651. out_dest[j++] = src[i];
  652. break;
  653. }
  654. }
  655. out_dest[j] = 0;
  656. return j;
  657. }
  658. /// Unescapes src to out_dest according to the format of the C compiler.
  659. /// Returns the length of the unescaped string.
  660. /// out_dest should be len+1 in size and can be the same buffer as src.
  661. ///
  662. /// @param out_dest Destination buffer
  663. /// @param src Source string
  664. /// @param len Length of the source string
  665. /// @return Length of the escaped string
  666. size_t sv_unescape_c(char* out_dest, const char* src, size_t len)
  667. {
  668. static unsigned char low2hex[256] = {
  669. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x0?
  670. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x1?
  671. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x2?
  672. 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,// 0x3?
  673. 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x4?
  674. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x5?
  675. 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x6?
  676. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x7?
  677. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x8?
  678. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x9?
  679. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xA?
  680. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xB?
  681. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xC?
  682. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xD?
  683. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xE?
  684. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 0xF?
  685. };
  686. size_t i;
  687. size_t j;
  688. for( i = 0, j = 0; i < len; )
  689. {
  690. if( src[i] == '\\' )
  691. {
  692. ++i;// '\\'
  693. if( i >= len )
  694. ShowWarning("sv_unescape_c: empty escape sequence\n");
  695. else if( src[i] == 'x' )
  696. {// hex escape sequence
  697. unsigned char c = 0;
  698. unsigned char inrange = 1;
  699. ++i;// 'x'
  700. if( i >= len || !ISXDIGIT(src[i]) )
  701. {
  702. ShowWarning("sv_unescape_c: \\x with no following hex digits\n");
  703. continue;
  704. }
  705. do{
  706. if( c > 0x0F && inrange )
  707. {
  708. ShowWarning("sv_unescape_c: hex escape sequence out of range\n");
  709. inrange = 0;
  710. }
  711. c = (c<<4)|low2hex[(unsigned char)src[i]];// hex digit
  712. ++i;
  713. }while( i < len && ISXDIGIT(src[i]) );
  714. out_dest[j++] = (char)c;
  715. }
  716. else if( src[i] == '0' || src[i] == '1' || src[i] == '2' || src[i] == '3' )
  717. {// octal escape sequence (255=0377)
  718. unsigned char c = src[i]-'0';
  719. ++i;// '0', '1', '2' or '3'
  720. if( i < len && src[i] >= '0' && src[i] <= '7' )
  721. {
  722. c = (c<<3)|(src[i]-'0');
  723. ++i;// octal digit
  724. }
  725. if( i < len && src[i] >= '0' && src[i] <= '7' )
  726. {
  727. c = (c<<3)|(src[i]-'0');
  728. ++i;// octal digit
  729. }
  730. out_dest[j++] = (char)c;
  731. }
  732. else
  733. {// other escape sequence
  734. if( strchr(SV_ESCAPE_C_SUPPORTED, src[i]) == nullptr )
  735. ShowWarning("sv_unescape_c: unknown escape sequence \\%c\n", src[i]);
  736. switch( src[i] )
  737. {
  738. case 'a': out_dest[j++] = '\a'; break;
  739. case 'b': out_dest[j++] = '\b'; break;
  740. case 't': out_dest[j++] = '\t'; break;
  741. case 'n': out_dest[j++] = '\n'; break;
  742. case 'v': out_dest[j++] = '\v'; break;
  743. case 'f': out_dest[j++] = '\f'; break;
  744. case 'r': out_dest[j++] = '\r'; break;
  745. case '?': out_dest[j++] = '\?'; break;
  746. default: out_dest[j++] = src[i]; break;
  747. }
  748. ++i;// escaped character
  749. }
  750. }
  751. else
  752. out_dest[j++] = src[i++];// normal character
  753. }
  754. out_dest[j] = 0;
  755. return j;
  756. }
  757. /// Skips a C escape sequence (starting with '\\').
  758. const char* skip_escaped_c(const char* p)
  759. {
  760. if( p && *p == '\\' )
  761. {
  762. ++p;
  763. switch( *p )
  764. {
  765. case 'x':// hexadecimal
  766. ++p;
  767. while( ISXDIGIT(*p) )
  768. ++p;
  769. break;
  770. case '0':
  771. case '1':
  772. case '2':
  773. case '3':// octal
  774. ++p;
  775. if( *p >= '0' && *p <= '7' )
  776. ++p;
  777. if( *p >= '0' && *p <= '7' )
  778. ++p;
  779. break;
  780. default:
  781. if( *p && strchr(SV_ESCAPE_C_SUPPORTED, *p) )
  782. ++p;
  783. }
  784. }
  785. return p;
  786. }
  787. /**
  788. * Opens and parses a file containing delim-separated columns, feeding them to the specified callback function row by row.
  789. * Tracks the progress of the operation (current line number, number of successfully processed rows).
  790. * Returns 'true' if it was able to process the specified file, or 'false' if it could not be read.
  791. * @param directory : Directory
  792. * @param filename : filename File to process
  793. * @param delim : delim Field delimiter
  794. * @param mincols : mincols Minimum number of columns of a valid row
  795. * @param maxcols : maxcols Maximum number of columns of a valid row
  796. * @param maxrows : maxcols Maximum number of columns of a valid row
  797. * @param parseproc : parseproc User-supplied row processing function
  798. * @param silent : should we display error if file not found ?
  799. * @return true on success, false if file could not be opened
  800. */
  801. bool sv_readdb( const char* directory, const char* filename, char delim, size_t mincols, size_t maxcols, size_t maxrows, bool (*parseproc)( char* fields[], size_t columns, size_t current ), bool silent ){
  802. FILE* fp;
  803. int32 lines = 0;
  804. size_t entries = 0;
  805. char** fields; // buffer for fields ([0] is reserved)
  806. char path[1024], *line;
  807. const short colsize=512;
  808. snprintf(path, sizeof(path), "%s/%s", directory, filename);
  809. // open file
  810. fp = fopen(path, "r");
  811. if( fp == nullptr )
  812. {
  813. if(silent == 0) ShowError("sv_readdb: can't read %s\n", path);
  814. return false;
  815. }
  816. // allocate enough memory for the maximum requested amount of columns plus the reserved one
  817. size_t nb_cols = maxcols + 1;
  818. fields = (char**)aMalloc(nb_cols*sizeof(char*));
  819. line = (char*)aMalloc(nb_cols*colsize);
  820. // process rows one by one
  821. while( fgets( line, static_cast<int32>( maxcols * colsize ), fp ) ){
  822. char *match;
  823. lines++;
  824. if( ( match = strstr(line, "//") ) != nullptr )
  825. {// strip comments
  826. match[0] = 0;
  827. }
  828. //trim(line); //TODO: strip trailing whitespace
  829. //trim2(line,1); //removing trailing actually break mob_skill_db
  830. if( line[0] == '\0' || line[0] == '\n' || line[0] == '\r')
  831. continue;
  832. bool error;
  833. size_t columns = sv_split( line, strlen( line ), 0, delim, fields, nb_cols, SV_TERMINATE_LF|SV_TERMINATE_CRLF, error );
  834. if( error ){
  835. ShowError( "sv_readdb: error in line %d of \"%s\".\n", lines, path );
  836. continue;
  837. }
  838. if( columns < mincols )
  839. {
  840. ShowError("sv_readdb: Insufficient columns in line %d of \"%s\" (found %d, need at least %d).\n", lines, path, columns, mincols);
  841. continue; // not enough columns
  842. }
  843. if( columns > maxcols )
  844. {
  845. ShowError("sv_readdb: Too many columns in line %d of \"%s\" (found %d, maximum is %d).\n", lines, path, columns, maxcols );
  846. continue; // too many columns
  847. }
  848. if( entries == maxrows )
  849. {
  850. ShowError("sv_readdb: Reached the maximum allowed number of entries (%d) when parsing file \"%s\".\n", maxrows, path);
  851. break;
  852. }
  853. // parse this row
  854. if( !parseproc(fields+1, columns, entries) )
  855. {
  856. ShowError("sv_readdb: Could not process contents of line %d of \"%s\".\n", lines, path);
  857. //perhaps call a provided function to clean entries if we have fail
  858. //clearproc(fields+1, columns, entries)
  859. continue; // invalid row contents
  860. }
  861. // success!
  862. entries++;
  863. }
  864. aFree(fields);
  865. aFree(line);
  866. fclose(fp);
  867. ShowStatus("Done reading '" CL_WHITE "%d" CL_RESET "' entries in '" CL_WHITE "%s" CL_RESET "'.\n", entries, path);
  868. return true;
  869. }
  870. /////////////////////////////////////////////////////////////////////
  871. // StringBuf - dynamic string
  872. //
  873. // @author MouseJstr (original)
  874. /// Allocates a StringBuf
  875. StringBuf* _StringBuf_Malloc(const char *file, int32 line, const char *func)
  876. {
  877. StringBuf* self;
  878. self = (StringBuf *)aCalloc2(1, sizeof(StringBuf), file, line, func);
  879. _StringBuf_Init(file, line, func, self);
  880. return self;
  881. }
  882. /// Initializes a previously allocated StringBuf
  883. void _StringBuf_Init(const char *file, int32 line, const char *func,StringBuf* self)
  884. {
  885. self->max_ = 1024;
  886. self->ptr_ = self->buf_ = (char*)aMalloc2(self->max_ + 1, file, line, func);
  887. }
  888. /// Appends the result of printf to the StringBuf
  889. size_t _StringBuf_Printf( const char* file, int32 line, const char* func, StringBuf* self, const char* fmt, ... ){
  890. va_list ap;
  891. va_start(ap, fmt);
  892. size_t len = _StringBuf_Vprintf(file,line,func,self, fmt, ap);
  893. va_end(ap);
  894. return len;
  895. }
  896. /// Appends the result of vprintf to the StringBuf
  897. size_t _StringBuf_Vprintf( const char* file, int32 line, const char* func, StringBuf* self, const char* fmt, va_list ap ){
  898. for(;;)
  899. {
  900. va_list apcopy;
  901. /* Try to print in the allocated space. */
  902. size_t size = self->max_ - (self->ptr_ - self->buf_);
  903. va_copy(apcopy, ap);
  904. int32 n = vsnprintf( self->ptr_, size, fmt, apcopy );
  905. va_end(apcopy);
  906. /* If that worked, return the length. */
  907. if( n > -1 && static_cast<size_t>(n) < size )
  908. {
  909. self->ptr_ += n;
  910. return self->ptr_ - self->buf_;
  911. }
  912. /* Else try again with more space. */
  913. self->max_ *= 2; // twice the old size
  914. size_t off = self->ptr_ - self->buf_;
  915. self->buf_ = (char*)aRealloc2(self->buf_, self->max_ + 1, file, line, func);
  916. self->ptr_ = self->buf_ + off;
  917. }
  918. }
  919. /// Appends the contents of another StringBuf to the StringBuf
  920. size_t _StringBuf_Append(const char *file, int32 line, const char *func,StringBuf* self, const StringBuf* sbuf)
  921. {
  922. size_t available = self->max_ - (self->ptr_ - self->buf_);
  923. size_t needed = sbuf->ptr_ - sbuf->buf_;
  924. if( needed >= available )
  925. {
  926. size_t off = self->ptr_ - self->buf_;
  927. self->max_ += needed;
  928. self->buf_ = (char*)aRealloc2(self->buf_, self->max_ + 1, file, line, func);
  929. self->ptr_ = self->buf_ + off;
  930. }
  931. memcpy(self->ptr_, sbuf->buf_, needed);
  932. self->ptr_ += needed;
  933. return self->ptr_ - self->buf_;
  934. }
  935. // Appends str to the StringBuf
  936. size_t _StringBuf_AppendStr(const char *file, int32 line, const char *func,StringBuf* self, const char* str)
  937. {
  938. size_t available = self->max_ - ( self->ptr_ - self->buf_ );
  939. size_t needed = strlen( str );
  940. if( needed >= available )
  941. {// not enough space, expand the buffer (minimum expansion = 1024)
  942. size_t off = self->ptr_ - self->buf_;
  943. self->max_ += std::max( needed, static_cast<size_t>( 1024 ) );
  944. self->buf_ = (char*)aRealloc2(self->buf_, self->max_ + 1, file, line, func);
  945. self->ptr_ = self->buf_ + off;
  946. }
  947. memcpy(self->ptr_, str, needed);
  948. self->ptr_ += needed;
  949. return self->ptr_ - self->buf_;
  950. }
  951. // Returns the length of the data in the Stringbuf
  952. int32 StringBuf_Length(StringBuf* self)
  953. {
  954. return (int32)(self->ptr_ - self->buf_);
  955. }
  956. /// Returns the data in the StringBuf
  957. char* StringBuf_Value(StringBuf* self)
  958. {
  959. *self->ptr_ = '\0';
  960. return self->buf_;
  961. }
  962. /// Clears the contents of the StringBuf
  963. void StringBuf_Clear(StringBuf* self)
  964. {
  965. self->ptr_ = self->buf_;
  966. }
  967. /// Destroys the StringBuf
  968. void StringBuf_Destroy(StringBuf* self)
  969. {
  970. aFree(self->buf_);
  971. self->ptr_ = self->buf_ = 0;
  972. self->max_ = 0;
  973. }
  974. // Frees a StringBuf returned by StringBuf_Malloc
  975. void StringBuf_Free(StringBuf* self)
  976. {
  977. StringBuf_Destroy(self);
  978. aFree(self);
  979. }