strlib.c 27 KB

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