str.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974
  1. /** @file str.c
  2. * @brief String related functions
  3. *
  4. * This file implements some often used string functions.
  5. * Some functions are more portable versions of standard
  6. * functions but others are original ones.
  7. */
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <assert.h>
  11. #include <stdio.h>
  12. #include <stdarg.h>
  13. #include "faux/ctype.h"
  14. #include "faux/conv.h"
  15. #include "faux/str.h"
  16. /** @brief Free the memory allocated for the string.
  17. *
  18. * Safely free the memory allocated for the string. You can use NULL
  19. * pointer with this function. POSIX's free() checks for the NULL pointer
  20. * but not all systems do so.
  21. *
  22. * @param [in] str String to free
  23. */
  24. void faux_str_free(char *str)
  25. {
  26. faux_free(str);
  27. }
  28. /** @brief Duplicates the string.
  29. *
  30. * Duplicates the string. Same as standard strdup() function. Allocates
  31. * memory with malloc(). Checks for NULL pointer.
  32. *
  33. * @warning Resulting string must be freed by faux_str_free().
  34. *
  35. * @param [in] str String to duplicate.
  36. * @return Pointer to allocated string or NULL.
  37. */
  38. char *faux_str_dup(const char *str)
  39. {
  40. if (!str)
  41. return NULL;
  42. return strdup(str);
  43. }
  44. /** @brief Duplicates the first n bytes of the string.
  45. *
  46. * Duplicates at most n bytes of the string. Allocates
  47. * memory with malloc(). Checks for NULL pointer. Function will allocate
  48. * n + 1 bytes to store string and terminating null byte.
  49. *
  50. * @warning Resulting string must be freed by faux_str_free().
  51. *
  52. * @param [in] str String to duplicate.
  53. * @param [in] n Number of bytes to copy.
  54. * @return Pointer to allocated string or NULL.
  55. */
  56. char *faux_str_dupn(const char *str, size_t n)
  57. {
  58. char *res = NULL;
  59. size_t len = 0;
  60. if (!str)
  61. return NULL;
  62. // Search for terminating '\0' among first n bytes
  63. // Don't use strlen() because it can be not null-terminated.
  64. for (len = 0; len < n; len++)
  65. if ('\0' == str[len])
  66. break;
  67. len = (len < n) ? len : n;
  68. res = faux_zmalloc(len + 1);
  69. if (!res)
  70. return NULL;
  71. strncpy(res, str, len);
  72. res[len] = '\0';
  73. return res;
  74. }
  75. /** @brief Generates lowercase copy of input string.
  76. *
  77. * Allocates the copy of input string and convert that copy to lowercase.
  78. *
  79. * @warning Resulting string must be freed by faux_str_free().
  80. *
  81. * @param [in] str String to convert.
  82. * @return Pointer to lowercase string copy or NULL.
  83. */
  84. char *faux_str_tolower(const char *str)
  85. {
  86. char *res = faux_str_dup(str);
  87. char *p = res;
  88. if (!res)
  89. return NULL;
  90. while (*p) {
  91. *p = faux_ctype_tolower(*p);
  92. p++;
  93. }
  94. return res;
  95. }
  96. /** @brief Generates uppercase copy of input string.
  97. *
  98. * Allocates the copy of input string and convert that copy to uppercase.
  99. *
  100. * @warning Resulting string must be freed by faux_str_free().
  101. *
  102. * @param [in] str String to convert.
  103. * @return Pointer to lowercase string copy or NULL.
  104. */
  105. char *faux_str_toupper(const char *str)
  106. {
  107. char *res = faux_str_dup(str);
  108. char *p = res;
  109. if (!res)
  110. return NULL;
  111. while (*p) {
  112. *p = faux_ctype_toupper(*p);
  113. p++;
  114. }
  115. return res;
  116. }
  117. /** @brief Add n bytes of text to existent string.
  118. *
  119. * Concatenate two strings. Add n bytes of second string to the end of the
  120. * first one. The first argument is address of string pointer. The pointer
  121. * can be changed due to realloc() features. The first pointer can be NULL.
  122. * In this case the memory will be malloc()-ed and stored to the first pointer.
  123. *
  124. * @param [in,out] str Address of first string pointer.
  125. * @param [in] text Text to add to the first string.
  126. * @param [in] n Number of bytes to add.
  127. * @return Pointer to resulting string or NULL.
  128. */
  129. char *faux_str_catn(char **str, const char *text, size_t n)
  130. {
  131. size_t str_len = 0;
  132. size_t text_len = 0;
  133. char *res = NULL;
  134. char *p = NULL;
  135. if (!text)
  136. return *str;
  137. str_len = (*str) ? strlen(*str) : 0;
  138. text_len = strlen(text);
  139. text_len = (text_len < n) ? text_len : n;
  140. res = realloc(*str, str_len + text_len + 1);
  141. if (!res)
  142. return NULL;
  143. p = res + str_len;
  144. strncpy(p, text, text_len);
  145. p[text_len] = '\0';
  146. *str = res;
  147. return res;
  148. }
  149. /** @brief Add some text to existent string.
  150. *
  151. * Concatenate two strings. Add second string to the end of the first one.
  152. * The first argument is address of string pointer. The pointer can be
  153. * changed due to realloc() features. The first pointer can be NULL. In this
  154. * case the memory will be malloc()-ed and stored to the first pointer.
  155. *
  156. * @param [in,out] str Address of first string pointer.
  157. * @param [in] text Text to add to the first string.
  158. * @return Pointer to resulting string or NULL.
  159. */
  160. char *faux_str_cat(char **str, const char *text)
  161. {
  162. size_t len = 0;
  163. if (!text)
  164. return *str;
  165. len = strlen(text);
  166. return faux_str_catn(str, text, len);
  167. }
  168. /** @brief Add multiply text strings to existent string.
  169. *
  170. * Concatenate multiply strings. Add next string to the end of the previous one.
  171. * The first argument is address of string pointer. The pointer can be
  172. * changed due to realloc() features. The first pointer can be NULL. In this
  173. * case the memory will be malloc()-ed and stored to the first pointer.
  174. * The last argument must be 'NULL'. It marks the last argument within
  175. * variable arguments list.
  176. *
  177. * @warning If last argument is not 'NULL' then behaviour is undefined.
  178. *
  179. * @param [in,out] str Address of first string pointer.
  180. * @param [in] text Text to add to the first string.
  181. * @return Pointer to resulting string or NULL.
  182. */
  183. char *faux_str_mcat(char **str, ...)
  184. {
  185. va_list ap;
  186. const char *arg = NULL;
  187. char *retval = *str;
  188. va_start(ap, str);
  189. while ((arg = va_arg(ap, const char *))) {
  190. retval = faux_str_cat(str, arg);
  191. }
  192. va_end(ap);
  193. return retval;
  194. }
  195. /** @brief Allocates memory and vsprintf() to it.
  196. *
  197. * Function tries to find out necessary amount of memory for specified format
  198. * string and arguments. Format is same as for vsprintf() function. Then
  199. * function allocates memory for resulting string and vsprintf() to it. So
  200. * user doesn't need to allocate buffer himself. Function returns allocated
  201. * string that need to be freed by faux_str_free() function later.
  202. *
  203. * @warning The returned pointer must be free by faux_str_free().
  204. *
  205. * @param [in] fmt Format string like the sprintf()'s fmt.
  206. * @param [in] ap The va_list argument.
  207. * @return Allocated resulting string or NULL on error.
  208. */
  209. char *faux_str_vsprintf(const char *fmt, va_list ap)
  210. {
  211. int size = 1;
  212. char calc_buf[1] = "";
  213. char *line = NULL;
  214. va_list ap2;
  215. // Calculate buffer size
  216. va_copy(ap2, ap);
  217. size = vsnprintf(calc_buf, size, fmt, ap2);
  218. va_end(ap2);
  219. // The snprintf() prior to 2.0.6 glibc version returns -1 if string
  220. // was truncated. The later glibc returns required buffer size.
  221. // The calc_buf can be NULL and size can be 0 for recent glibc but
  222. // probably some exotic implementations can break on it. So use
  223. // minimal buffer with length = 1.
  224. if (size < 0)
  225. return NULL;
  226. size++; // Additional byte for '\0'
  227. line = faux_zmalloc(size);
  228. if (!line) // Memory problems
  229. return NULL;
  230. // Format real string
  231. size = vsnprintf(line, size, fmt, ap);
  232. if (size < 0) { // Some problems
  233. faux_str_free(line);
  234. return NULL;
  235. }
  236. return line;
  237. }
  238. /** @brief Allocates memory and sprintf() to it.
  239. *
  240. * Function tries to find out necessary amount of memory for specified format
  241. * string and arguments. Format is same as for sprintf() function. Then
  242. * function allocates memory for resulting string and sprintf() to it. So
  243. * user doesn't need to allocate buffer himself. Function returns allocated
  244. * string that need to be freed by faux_str_free() function later.
  245. *
  246. * @warning The returned pointer must be free by faux_str_free().
  247. *
  248. * @param [in] fmt Format string like the sprintf()'s fmt.
  249. * @param [in] arg Number of arguments.
  250. * @return Allocated resulting string or NULL on error.
  251. */
  252. char *faux_str_sprintf(const char *fmt, ...)
  253. {
  254. char *line = NULL;
  255. va_list ap;
  256. va_start(ap, fmt);
  257. line = faux_str_vsprintf(fmt, ap);
  258. va_end(ap);
  259. return line;
  260. }
  261. /** @brief Service function to compare two chars in right way.
  262. *
  263. * The problem is char type can be signed or unsigned on different
  264. * platforms. So stright comparision can return different results.
  265. *
  266. * @param [in] char1 First char
  267. * @param [in] char2 Second char
  268. * @return
  269. * < 0 if char1 < char2
  270. * = 0 if char1 = char2
  271. * > 0 if char1 > char2
  272. */
  273. static int faux_str_cmp_chars(char char1, char char2)
  274. {
  275. unsigned char ch1 = (unsigned char)char1;
  276. unsigned char ch2 = (unsigned char)char2;
  277. return (int)ch1 - (int)ch2;
  278. }
  279. /** @brief Compare n first characters of two strings.
  280. *
  281. * @param [in] str1 First string to compare.
  282. * @param [in] str2 Second string to compare.
  283. * @param [in] n Number of characters to compare.
  284. * @return < 0, 0, > 0, see the strcasecmp().
  285. */
  286. int faux_str_cmpn(const char *str1, const char *str2, size_t n)
  287. {
  288. if (!str1 && !str2) // Empty strings are equal
  289. return 0;
  290. if (!str1) // Consider NULL string to be less then empty string
  291. return -1;
  292. if (!str2) // Consider NULL string to be less then empty string
  293. return 1;
  294. return strncmp(str1, str2, n);
  295. }
  296. /** @brief Compare two strings.
  297. *
  298. * @param [in] str1 First string to compare.
  299. * @param [in] str2 Second string to compare.
  300. * @return < 0, 0, > 0, see the strcmp().
  301. */
  302. int faux_str_cmp(const char *str1, const char *str2)
  303. {
  304. if (!str1 && !str2) // Empty strings are equal
  305. return 0;
  306. if (!str1) // Consider NULL string to be less then empty string
  307. return -1;
  308. if (!str2) // Consider NULL string to be less then empty string
  309. return 1;
  310. return strcmp(str1, str2);
  311. }
  312. /** @brief Compare n first characters of two strings ignoring case.
  313. *
  314. * The difference beetween this function an standard strncasecmp() is
  315. * faux function uses faux ctype functions. It can be important for
  316. * portability.
  317. *
  318. * @param [in] str1 First string to compare.
  319. * @param [in] str2 Second string to compare.
  320. * @param [in] n Number of characters to compare.
  321. * @return < 0, 0, > 0, see the strcasecmp().
  322. */
  323. int faux_str_casecmpn(const char *str1, const char *str2, size_t n)
  324. {
  325. const char *p1 = str1;
  326. const char *p2 = str2;
  327. size_t num = n;
  328. while (*p1 != '\0' && *p2 != '\0' && num != 0) {
  329. int res = faux_str_cmp_chars(
  330. faux_ctype_tolower(*p1), faux_ctype_tolower(*p2));
  331. if (res != 0)
  332. return res;
  333. p1++;
  334. p2++;
  335. num--;
  336. }
  337. if (0 == n) // It means n first characters are equal.
  338. return 0;
  339. return faux_str_cmp_chars(
  340. faux_ctype_tolower(*p1), faux_ctype_tolower(*p2));
  341. }
  342. /** @brief Compare two strings ignoring case.
  343. *
  344. * The difference beetween this function an standard strcasecmp() is
  345. * faux function uses faux ctype functions. It can be important for
  346. * portability.
  347. *
  348. * @param [in] str1 First string to compare.
  349. * @param [in] str2 Second string to compare.
  350. * @return < 0, 0, > 0, see the strcasecmp().
  351. */
  352. int faux_str_casecmp(const char *str1, const char *str2)
  353. {
  354. const char *p1 = str1;
  355. const char *p2 = str2;
  356. if (!p1 && !p2) // Empty strings are equal
  357. return 0;
  358. if (!p1) // Consider NULL string to be less then empty string
  359. return -1;
  360. if (!p2) // Consider NULL string to be less then empty string
  361. return 1;
  362. while (*p1 != '\0' && *p2 != '\0') {
  363. int res = faux_str_cmp_chars(
  364. faux_ctype_tolower(*p1), faux_ctype_tolower(*p2));
  365. if (res != 0)
  366. return res;
  367. p1++;
  368. p2++;
  369. }
  370. return faux_str_cmp_chars(
  371. faux_ctype_tolower(*p1), faux_ctype_tolower(*p2));
  372. }
  373. /** @brief Compare two strings considering numbers.
  374. *
  375. * "a2" < "a10"
  376. *
  377. * @param [in] str1 First string to compare.
  378. * @param [in] str2 Second string to compare.
  379. * @return < 0, 0, > 0, see the strcasecmp().
  380. */
  381. int faux_str_numcmp(const char *str1, const char *str2)
  382. {
  383. const char *p1 = str1;
  384. const char *p2 = str2;
  385. if (!p1 && !p2) // Empty strings are equal
  386. return 0;
  387. if (!p1) // Consider NULL string to be less then empty string
  388. return -1;
  389. if (!p2) // Consider NULL string to be less then empty string
  390. return 1;
  391. while (*p1 != '\0' && *p2 != '\0') {
  392. if (faux_ctype_isdigit(*p1) && faux_ctype_isdigit(*p2)) {
  393. unsigned long long int v1 = 0;
  394. unsigned long long int v2 = 0;
  395. if (!faux_conv_atoull(p1, &v1, 10) ||
  396. !faux_conv_atoull(p2, &v2, 10)) // Overflow?
  397. return faux_str_cmp(str1, str2); // Standard comparison
  398. if (v1 > v2)
  399. return 1;
  400. if (v1 < v2)
  401. return -1;
  402. // Skip all digits if equal
  403. while (faux_ctype_isdigit(*p1))
  404. p1++;
  405. while (faux_ctype_isdigit(*p2))
  406. p2++;
  407. } else {
  408. int res = faux_str_cmp_chars(*p1, *p2);
  409. if (res != 0)
  410. return res;
  411. p1++;
  412. p2++;
  413. }
  414. }
  415. return faux_str_cmp_chars(*p1, *p2);
  416. }
  417. /** @brief Finds the first occurrence of the substring in the string
  418. *
  419. * Function is a faux version of strcasestr() function.
  420. *
  421. * @param [in] haystack String to find substring in it.
  422. * @param [in] needle Substring to find.
  423. * @return
  424. * Pointer to first occurence of substring in the string.
  425. * NULL on error
  426. */
  427. char *faux_str_casestr(const char *haystack, const char *needle)
  428. {
  429. const char *ptr = haystack;
  430. size_t ptr_len = 0;
  431. size_t needle_len = 0;
  432. if (!haystack || !needle)
  433. return NULL;
  434. ptr_len = strlen(haystack);
  435. needle_len = strlen(needle);
  436. while ((*ptr != '\0') && (ptr_len >= needle_len)) {
  437. int res = faux_str_casecmpn(ptr, needle, needle_len);
  438. if (0 == res)
  439. return (char *)ptr;
  440. ptr++;
  441. ptr_len--;
  442. }
  443. return NULL; // Not found
  444. }
  445. /** Prepare string for embedding to C-code (make escaping).
  446. *
  447. * @warning The returned pointer must be freed by faux_str_free().
  448. * @param [in] src String for escaping.
  449. * @return Escaped string or NULL on error.
  450. */
  451. char *faux_str_c_esc(const char *src)
  452. {
  453. const char *src_ptr = src;
  454. char *dst = NULL;
  455. char *dst_ptr = NULL;
  456. char *escaped = NULL;
  457. size_t src_len = 0;
  458. size_t dst_len = 0;
  459. if (!src)
  460. return NULL;
  461. src_len = strlen(src);
  462. // Calculate max destination string size.
  463. // The worst case is when each src character will be replaced by
  464. // something like '\xff'. So it's 4 dst chars for 1 src one.
  465. dst_len = (src_len * 4) + 1; // one byte for '\0'
  466. dst = faux_zmalloc(dst_len);
  467. assert(dst);
  468. if (!dst)
  469. return NULL;
  470. dst_ptr = dst;
  471. while (*src_ptr != '\0') {
  472. char *esc = NULL; // escaped replacement
  473. char buf[5]; // longest 'char' (4 bytes) + '\0'
  474. size_t len = 0;
  475. switch (*src_ptr) {
  476. case '\n':
  477. esc = "\\n";
  478. break;
  479. case '\"':
  480. esc = "\\\"";
  481. break;
  482. case '\\':
  483. esc = "\\\\";
  484. break;
  485. case '\'':
  486. esc = "\\\'";
  487. break;
  488. case '\r':
  489. esc = "\\r";
  490. break;
  491. case '\t':
  492. esc = "\\t";
  493. break;
  494. default:
  495. // Check is the symbol control character. Control
  496. // characters has codes from 0x00 to 0x1f.
  497. if (((unsigned char)*src_ptr & 0xe0) == 0) { // control
  498. snprintf(buf, sizeof(buf), "\\x%02x",
  499. (unsigned char)*src_ptr);
  500. buf[4] = '\0'; // for safety
  501. } else {
  502. buf[0] = *src_ptr; // Common character
  503. buf[1] = '\0';
  504. }
  505. esc = buf;
  506. break;
  507. }
  508. len = strlen(esc);
  509. memcpy(dst_ptr, esc, len); // zmalloc() nullify the rest
  510. dst_ptr += len;
  511. src_ptr++;
  512. }
  513. escaped = faux_str_dup(dst); // Free some memory
  514. faux_str_free(dst); // 'dst' size >= 'escaped' size
  515. return escaped;
  516. }
  517. #define BYTE_CONV_LEN 4 // Length of one byte converted to string
  518. /** Prepare binary block for embedding to C-code.
  519. *
  520. * @warning The returned pointer must be freed by faux_str_free().
  521. * @param [in] src Binary block for conversion.
  522. * @return C-string or NULL on error.
  523. */
  524. char *faux_str_c_bin(const char *src, size_t n)
  525. {
  526. const char *src_ptr = src;
  527. char *dst = NULL;
  528. char *dst_ptr = NULL;
  529. size_t dst_len = 0;
  530. if (!src)
  531. return NULL;
  532. // Calculate destination string size.
  533. // Each src character will be replaced by
  534. // something like '\xff'. So it's 4 dst chars for 1 src char.
  535. dst_len = (n * BYTE_CONV_LEN) + 1; // one byte for '\0'
  536. dst = faux_zmalloc(dst_len);
  537. assert(dst);
  538. if (!dst)
  539. return NULL;
  540. dst_ptr = dst;
  541. while (src_ptr < (src + n)) {
  542. char buf[BYTE_CONV_LEN + 1]; // longest 'char' (4 bytes) + '\0'
  543. snprintf(buf, sizeof(buf), "\\x%02x", (unsigned char)*src_ptr);
  544. memcpy(dst_ptr, buf, BYTE_CONV_LEN); // zmalloc() nullify the rest
  545. dst_ptr += BYTE_CONV_LEN;
  546. src_ptr++;
  547. }
  548. return dst;
  549. }
  550. /** @brief Search the n-th chars of string for one of the specified chars.
  551. *
  552. * The function search for any of specified characters within string.
  553. * The search is limited to first n characters of the string. If
  554. * terminating '\0' is before n-th character then search will stop on
  555. * it. Can be used with raw memory block.
  556. *
  557. * @param [in] str String (or memory block) to search in.
  558. * @param [in] chars_to_string Chars enumeration to search for.
  559. * @param [in] n Maximum number of bytes to search within.
  560. * @return Pointer to the first occurence of one of specified chars.
  561. * NULL on error.
  562. */
  563. char *faux_str_charsn(const char *str, const char *chars_to_search, size_t n)
  564. {
  565. const char *current_char = str;
  566. size_t len = n;
  567. if (!str || !chars_to_search)
  568. return NULL;
  569. while ((len > 0) && (*current_char != '\0')) {
  570. if (strchr(chars_to_search, *current_char))
  571. return (char *)current_char;
  572. current_char++;
  573. len--;
  574. }
  575. return NULL;
  576. }
  577. /** @brief Search string for one of the specified chars.
  578. *
  579. * The function search for any of specified characters within string.
  580. *
  581. * @param [in] str String to search in.
  582. * @param [in] chars_to_string Chars enumeration to search for.
  583. * @return Pointer to the first occurence of one of specified chars.
  584. * NULL on error.
  585. */
  586. char *faux_str_chars(const char *str, const char *chars_to_search)
  587. {
  588. if (!str)
  589. return NULL;
  590. return faux_str_charsn(str, chars_to_search, strlen(str));
  591. }
  592. /** @brief Remove escaping. Convert string to internal view.
  593. *
  594. * Find backslashes (before escaped symbols) and remove it. Escaped symbol
  595. * will not be analyzed so `\\` will lead to `\`.
  596. *
  597. * @param [in] string Escaped string.
  598. * @param [in] len Length of string to de-escape.
  599. * @return Allocated de-escaped string
  600. * @warning Returned value must be freed by faux_str_free() later.
  601. */
  602. static char *faux_str_deesc(const char *string, size_t len)
  603. {
  604. const char *s = string;
  605. char *res = NULL;
  606. char *p = NULL;
  607. bool_t escaped = BOOL_FALSE;
  608. if (!string)
  609. return NULL;
  610. if (0 == len)
  611. return NULL;
  612. res = faux_zmalloc(len + 1);
  613. assert(res);
  614. if (!res)
  615. return NULL;
  616. p = res;
  617. while ((*s != '\0') && (s < (string +len))) {
  618. if (('\\' == *s) && !escaped) {
  619. escaped = BOOL_TRUE;
  620. s++;
  621. continue;
  622. }
  623. escaped = BOOL_FALSE;
  624. *p = *s;
  625. s++;
  626. p++;
  627. }
  628. *p = '\0';
  629. return res;
  630. }
  631. /*--------------------------------------------------------- */
  632. /** @brief Find next word or quoted substring within string
  633. *
  634. * The quotation can be of several different kinds.
  635. *
  636. * The first kind is standard double quoting. In this case the internal (within
  637. * quotation) `"` and `\` symbols must be escaped. But symbols will be deescaped
  638. * before writing to internal buffers.
  639. *
  640. * The second kind of quotation is alternative quotation. Any symbol can become
  641. * quote sign. For example "`" and "'" can be considered as a quotes. To use
  642. * some symbols as a quote them must be specified by `alt_quotes` function
  643. * parameter. The single symbol can be considered as a start of quotation or
  644. * a sequence of the same symbols can be considered as a start of quotation. In
  645. * this case the end of quotation is a sequence of the same symbols. The same
  646. * symbol can appear inside quotation but number of symbols (sequence) must be
  647. * less than opening quote sequence. The example of alternatively quoted string
  648. * is ```some text``and anothe`r```. The backslash has no special meaning inside
  649. * quoted string.
  650. *
  651. * The substring can be unquoted string without spaces. The space, backslash and
  652. * quote can be escaped by backslash.
  653. *
  654. * Parts of text with different quotes can be glued together to get single
  655. * substring like this: aaa"inside dbl quote"bbb``alt quote"`here``ccc.
  656. *
  657. * @param [in] str String to parse.
  658. * @param [out] saveptr Pointer to first symbol after found substring.
  659. * @param [in] alt_quotes Possible alternative quotes.
  660. * @param [out] qclosed Flag is quote closed.
  661. * @return Allocated buffer with found substring (without quotes).
  662. * @warning Returned alocated buffer must be freed later by faux_str_free()
  663. */
  664. char *faux_str_nextword(const char *str, const char **saveptr,
  665. const char *alt_quotes, bool_t *qclosed)
  666. {
  667. const char *string = str;
  668. const char *word = NULL;
  669. size_t len = 0;
  670. const char dbl_quote = '"';
  671. bool_t dbl_quoted = BOOL_FALSE;
  672. char alt_quote = '\0';
  673. unsigned int alt_quote_num = 0; // Number of opening alt quotes
  674. bool_t alt_quoted = BOOL_FALSE;
  675. char *result = NULL;
  676. // Find the start of a word (not including an opening quote)
  677. while (*string && isspace(*string))
  678. string++;
  679. word = string; // Suppose not quoted string
  680. while (*string != '\0') {
  681. // Standard double quotation
  682. if (dbl_quoted) {
  683. // End of word
  684. if (*string == dbl_quote) {
  685. if (len > 0) {
  686. char *s = faux_str_deesc(word, len);
  687. faux_str_cat(&result, s);
  688. faux_str_free(s);
  689. }
  690. dbl_quoted = BOOL_FALSE;
  691. string++;
  692. word = string;
  693. len = 0;
  694. // Escaping
  695. } else if (*string == '\\') {
  696. // Skip escaping
  697. string++;
  698. len++;
  699. // Skip escaped symbol
  700. if (*string) {
  701. string++;
  702. len++;
  703. }
  704. } else {
  705. string++;
  706. len++;
  707. }
  708. // Alternative multi quotation
  709. } else if (alt_quoted) {
  710. unsigned int qnum = alt_quote_num;
  711. while (string && (*string == alt_quote) && qnum) {
  712. string++;
  713. len++;
  714. qnum--;
  715. }
  716. if (0 == qnum) { // End of word was found
  717. // Quotes themselfs are not a part of a word
  718. len -= alt_quote_num;
  719. if (len > 0)
  720. faux_str_catn(&result, word, len);
  721. alt_quoted = BOOL_FALSE;
  722. word = string;
  723. len = 0;
  724. } else if (qnum == alt_quote_num) { // No quote syms
  725. string++;
  726. len++;
  727. }
  728. // Not quoted
  729. } else {
  730. // Start of a double quoted string
  731. if (*string == dbl_quote) {
  732. if (len > 0) {
  733. char *s = faux_str_deesc(word, len);
  734. faux_str_cat(&result, s);
  735. faux_str_free(s);
  736. }
  737. dbl_quoted = BOOL_TRUE;
  738. string++;
  739. word = string;
  740. len = 0;
  741. // Start of alt quoted string
  742. } else if (alt_quotes && strchr(alt_quotes, *string)) {
  743. if (len > 0) {
  744. char *s = faux_str_deesc(word, len);
  745. faux_str_cat(&result, s);
  746. faux_str_free(s);
  747. }
  748. alt_quoted = BOOL_TRUE;
  749. alt_quote = *string;
  750. alt_quote_num = 0;
  751. while (string && (*string == alt_quote)) {
  752. string++;
  753. alt_quote_num++; // Count starting quotes
  754. }
  755. word = string;
  756. len = 0;
  757. // End of word
  758. } else if (isspace(*string)) {
  759. if (len > 0) {
  760. char *s = faux_str_deesc(word, len);
  761. faux_str_cat(&result, s);
  762. faux_str_free(s);
  763. }
  764. word = string;
  765. len = 0;
  766. break;
  767. // Escaping
  768. } else if (*string == '\\') {
  769. // Skip escaping
  770. string++;
  771. len++;
  772. // Skip escaped symbol
  773. if (*string) {
  774. string++;
  775. len++;
  776. }
  777. } else {
  778. string++;
  779. len++;
  780. }
  781. }
  782. }
  783. if (len > 0) {
  784. if (alt_quoted) {
  785. faux_str_catn(&result, word, len);
  786. } else {
  787. char *s = faux_str_deesc(word, len);
  788. faux_str_cat(&result, s);
  789. faux_str_free(s);
  790. }
  791. }
  792. if (saveptr)
  793. *saveptr = string;
  794. if (qclosed)
  795. *qclosed = ! (dbl_quoted || alt_quoted);
  796. return result;
  797. }
  798. /** @brief Indicates is string is empty.
  799. *
  800. * @param [in] str String to analyze.
  801. * @return BOOL_TRUE if pointer is NULL or empty, BOOL_FALSE if not empty.
  802. */
  803. bool_t faux_str_is_empty(const char *str)
  804. {
  805. if (!str)
  806. return BOOL_TRUE;
  807. if ('\0' == *str)
  808. return BOOL_TRUE;
  809. return BOOL_FALSE;
  810. }
  811. /** @brief Gets line from multiline string.
  812. *
  813. * @param [in] str String to analyze.
  814. * @param [out] saveptr Pointer to the position after found EOL.
  815. * @return Allocated line or NULL if string is empty.
  816. */
  817. char *faux_str_getline(const char *str, const char **saveptr)
  818. {
  819. const char *find_pos = NULL;
  820. const char *eol = "\n\r";
  821. if (!str)
  822. return NULL;
  823. if ('\0' == *str) {
  824. if (saveptr)
  825. *saveptr = str;
  826. return NULL;
  827. }
  828. find_pos = faux_str_chars(str, eol);
  829. if (find_pos) {
  830. size_t len = find_pos - str;
  831. char *res = NULL;
  832. res = faux_zmalloc(len + 1);
  833. if (len > 0)
  834. memcpy(res, str, len);
  835. if (saveptr)
  836. *saveptr = find_pos + 1;
  837. return res;
  838. }
  839. // Line without EOL
  840. if (saveptr)
  841. *saveptr = str + strlen(str);
  842. return faux_str_dup(str);
  843. }