str.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983
  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. assert(haystack);
  433. assert(needle);
  434. if (!haystack || !needle)
  435. return NULL;
  436. ptr_len = strlen(haystack);
  437. needle_len = strlen(needle);
  438. while ((*ptr != '\0') && (ptr_len >= needle_len)) {
  439. int res = faux_str_casecmpn(ptr, needle, needle_len);
  440. if (0 == res)
  441. return (char *)ptr;
  442. ptr++;
  443. ptr_len--;
  444. }
  445. return NULL; // Not found
  446. }
  447. /** Prepare string for embedding to C-code (make escaping).
  448. *
  449. * @warning The returned pointer must be freed by faux_str_free().
  450. * @param [in] src String for escaping.
  451. * @return Escaped string or NULL on error.
  452. */
  453. char *faux_str_c_esc(const char *src)
  454. {
  455. const char *src_ptr = src;
  456. char *dst = NULL;
  457. char *dst_ptr = NULL;
  458. char *escaped = NULL;
  459. size_t src_len = 0;
  460. size_t dst_len = 0;
  461. assert(src);
  462. if (!src)
  463. return NULL;
  464. src_len = strlen(src);
  465. // Calculate max destination string size.
  466. // The worst case is when each src character will be replaced by
  467. // something like '\xff'. So it's 4 dst chars for 1 src one.
  468. dst_len = (src_len * 4) + 1; // one byte for '\0'
  469. dst = faux_zmalloc(dst_len);
  470. assert(dst);
  471. if (!dst)
  472. return NULL;
  473. dst_ptr = dst;
  474. while (*src_ptr != '\0') {
  475. char *esc = NULL; // escaped replacement
  476. char buf[5]; // longest 'char' (4 bytes) + '\0'
  477. size_t len = 0;
  478. switch (*src_ptr) {
  479. case '\n':
  480. esc = "\\n";
  481. break;
  482. case '\"':
  483. esc = "\\\"";
  484. break;
  485. case '\\':
  486. esc = "\\\\";
  487. break;
  488. case '\'':
  489. esc = "\\\'";
  490. break;
  491. case '\r':
  492. esc = "\\r";
  493. break;
  494. case '\t':
  495. esc = "\\t";
  496. break;
  497. default:
  498. // Check is the symbol control character. Control
  499. // characters has codes from 0x00 to 0x1f.
  500. if (((unsigned char)*src_ptr & 0xe0) == 0) { // control
  501. snprintf(buf, sizeof(buf), "\\x%02x",
  502. (unsigned char)*src_ptr);
  503. buf[4] = '\0'; // for safety
  504. } else {
  505. buf[0] = *src_ptr; // Common character
  506. buf[1] = '\0';
  507. }
  508. esc = buf;
  509. break;
  510. }
  511. len = strlen(esc);
  512. memcpy(dst_ptr, esc, len); // zmalloc() nullify the rest
  513. dst_ptr += len;
  514. src_ptr++;
  515. }
  516. escaped = faux_str_dup(dst); // Free some memory
  517. faux_str_free(dst); // 'dst' size >= 'escaped' size
  518. return escaped;
  519. }
  520. #define BYTE_CONV_LEN 4 // Length of one byte converted to string
  521. /** Prepare binary block for embedding to C-code.
  522. *
  523. * @warning The returned pointer must be freed by faux_str_free().
  524. * @param [in] src Binary block for conversion.
  525. * @return C-string or NULL on error.
  526. */
  527. char *faux_str_c_bin(const char *src, size_t n)
  528. {
  529. const char *src_ptr = src;
  530. char *dst = NULL;
  531. char *dst_ptr = NULL;
  532. size_t dst_len = 0;
  533. assert(src);
  534. if (!src)
  535. return NULL;
  536. // Calculate destination string size.
  537. // Each src character will be replaced by
  538. // something like '\xff'. So it's 4 dst chars for 1 src char.
  539. dst_len = (n * BYTE_CONV_LEN) + 1; // one byte for '\0'
  540. dst = faux_zmalloc(dst_len);
  541. assert(dst);
  542. if (!dst)
  543. return NULL;
  544. dst_ptr = dst;
  545. while (src_ptr < (src + n)) {
  546. char buf[BYTE_CONV_LEN + 1]; // longest 'char' (4 bytes) + '\0'
  547. snprintf(buf, sizeof(buf), "\\x%02x", (unsigned char)*src_ptr);
  548. memcpy(dst_ptr, buf, BYTE_CONV_LEN); // zmalloc() nullify the rest
  549. dst_ptr += BYTE_CONV_LEN;
  550. src_ptr++;
  551. }
  552. return dst;
  553. }
  554. /** @brief Search the n-th chars of string for one of the specified chars.
  555. *
  556. * The function search for any of specified characters within string.
  557. * The search is limited to first n characters of the string. If
  558. * terminating '\0' is before n-th character then search will stop on
  559. * it. Can be used with raw memory block.
  560. *
  561. * @param [in] str String (or memory block) to search in.
  562. * @param [in] chars_to_string Chars enumeration to search for.
  563. * @param [in] n Maximum number of bytes to search within.
  564. * @return Pointer to the first occurence of one of specified chars.
  565. * NULL on error.
  566. */
  567. char *faux_str_charsn(const char *str, const char *chars_to_search, size_t n)
  568. {
  569. const char *current_char = str;
  570. size_t len = n;
  571. assert(str);
  572. assert(chars_to_search);
  573. if (!str || !chars_to_search)
  574. return NULL;
  575. while ((len > 0) && (*current_char != '\0')) {
  576. if (strchr(chars_to_search, *current_char))
  577. return (char *)current_char;
  578. current_char++;
  579. len--;
  580. }
  581. return NULL;
  582. }
  583. /** @brief Search string for one of the specified chars.
  584. *
  585. * The function search for any of specified characters within string.
  586. *
  587. * @param [in] str String to search in.
  588. * @param [in] chars_to_string Chars enumeration to search for.
  589. * @return Pointer to the first occurence of one of specified chars.
  590. * NULL on error.
  591. */
  592. char *faux_str_chars(const char *str, const char *chars_to_search)
  593. {
  594. assert(str);
  595. if (!str)
  596. return NULL;
  597. return faux_str_charsn(str, chars_to_search, strlen(str));
  598. }
  599. /** @brief Remove escaping. Convert string to internal view.
  600. *
  601. * Find backslashes (before escaped symbols) and remove it. Escaped symbol
  602. * will not be analyzed so `\\` will lead to `\`.
  603. *
  604. * @param [in] string Escaped string.
  605. * @param [in] len Length of string to de-escape.
  606. * @return Allocated de-escaped string
  607. * @warning Returned value must be freed by faux_str_free() later.
  608. */
  609. static char *faux_str_deesc(const char *string, size_t len)
  610. {
  611. const char *s = string;
  612. char *res = NULL;
  613. char *p = NULL;
  614. bool_t escaped = BOOL_FALSE;
  615. assert(string);
  616. if (!string)
  617. return NULL;
  618. if (0 == len)
  619. return NULL;
  620. res = faux_zmalloc(len + 1);
  621. assert(res);
  622. if (!res)
  623. return NULL;
  624. p = res;
  625. while ((*s != '\0') && (s < (string +len))) {
  626. if (('\\' == *s) && !escaped) {
  627. escaped = BOOL_TRUE;
  628. s++;
  629. continue;
  630. }
  631. escaped = BOOL_FALSE;
  632. *p = *s;
  633. s++;
  634. p++;
  635. }
  636. *p = '\0';
  637. return res;
  638. }
  639. /*--------------------------------------------------------- */
  640. /** @brief Find next word or quoted substring within string
  641. *
  642. * The quotation can be of several different kinds.
  643. *
  644. * The first kind is standard double quoting. In this case the internal (within
  645. * quotation) `"` and `\` symbols must be escaped. But symbols will be deescaped
  646. * before writing to internal buffers.
  647. *
  648. * The second kind of quotation is alternative quotation. Any symbol can become
  649. * quote sign. For example "`" and "'" can be considered as a quotes. To use
  650. * some symbols as a quote them must be specified by `alt_quotes` function
  651. * parameter. The single symbol can be considered as a start of quotation or
  652. * a sequence of the same symbols can be considered as a start of quotation. In
  653. * this case the end of quotation is a sequence of the same symbols. The same
  654. * symbol can appear inside quotation but number of symbols (sequence) must be
  655. * less than opening quote sequence. The example of alternatively quoted string
  656. * is ```some text``and anothe`r```. The backslash has no special meaning inside
  657. * quoted string.
  658. *
  659. * The substring can be unquoted string without spaces. The space, backslash and
  660. * quote can be escaped by backslash.
  661. *
  662. * Parts of text with different quotes can be glued together to get single
  663. * substring like this: aaa"inside dbl quote"bbb``alt quote"`here``ccc.
  664. *
  665. * @param [in] str String to parse.
  666. * @param [out] saveptr Pointer to first symbol after found substring.
  667. * @param [in] alt_quotes Possible alternative quotes.
  668. * @param [out] qclosed Flag is quote closed.
  669. * @return Allocated buffer with found substring (without quotes).
  670. * @warning Returned alocated buffer must be freed later by faux_str_free()
  671. */
  672. char *faux_str_nextword(const char *str, const char **saveptr,
  673. const char *alt_quotes, bool_t *qclosed)
  674. {
  675. const char *string = str;
  676. const char *word = NULL;
  677. size_t len = 0;
  678. const char dbl_quote = '"';
  679. bool_t dbl_quoted = BOOL_FALSE;
  680. char alt_quote = '\0';
  681. unsigned int alt_quote_num = 0; // Number of opening alt quotes
  682. bool_t alt_quoted = BOOL_FALSE;
  683. char *result = NULL;
  684. // Find the start of a word (not including an opening quote)
  685. while (*string && isspace(*string))
  686. string++;
  687. word = string; // Suppose not quoted string
  688. while (*string != '\0') {
  689. // Standard double quotation
  690. if (dbl_quoted) {
  691. // End of word
  692. if (*string == dbl_quote) {
  693. if (len > 0) {
  694. char *s = faux_str_deesc(word, len);
  695. faux_str_cat(&result, s);
  696. faux_str_free(s);
  697. }
  698. dbl_quoted = BOOL_FALSE;
  699. string++;
  700. word = string;
  701. len = 0;
  702. // Escaping
  703. } else if (*string == '\\') {
  704. // Skip escaping
  705. string++;
  706. len++;
  707. // Skip escaped symbol
  708. if (*string) {
  709. string++;
  710. len++;
  711. }
  712. } else {
  713. string++;
  714. len++;
  715. }
  716. // Alternative multi quotation
  717. } else if (alt_quoted) {
  718. unsigned int qnum = alt_quote_num;
  719. while (string && (*string == alt_quote) && qnum) {
  720. string++;
  721. len++;
  722. qnum--;
  723. }
  724. if (0 == qnum) { // End of word was found
  725. // Quotes themselfs are not a part of a word
  726. len -= alt_quote_num;
  727. if (len > 0)
  728. faux_str_catn(&result, word, len);
  729. alt_quoted = BOOL_FALSE;
  730. word = string;
  731. len = 0;
  732. } else if (qnum == alt_quote_num) { // No quote syms
  733. string++;
  734. len++;
  735. }
  736. // Not quoted
  737. } else {
  738. // Start of a double quoted string
  739. if (*string == dbl_quote) {
  740. if (len > 0) {
  741. char *s = faux_str_deesc(word, len);
  742. faux_str_cat(&result, s);
  743. faux_str_free(s);
  744. }
  745. dbl_quoted = BOOL_TRUE;
  746. string++;
  747. word = string;
  748. len = 0;
  749. // Start of alt quoted string
  750. } else if (alt_quotes && strchr(alt_quotes, *string)) {
  751. if (len > 0) {
  752. char *s = faux_str_deesc(word, len);
  753. faux_str_cat(&result, s);
  754. faux_str_free(s);
  755. }
  756. alt_quoted = BOOL_TRUE;
  757. alt_quote = *string;
  758. alt_quote_num = 0;
  759. while (string && (*string == alt_quote)) {
  760. string++;
  761. alt_quote_num++; // Count starting quotes
  762. }
  763. word = string;
  764. len = 0;
  765. // End of word
  766. } else if (isspace(*string)) {
  767. if (len > 0) {
  768. char *s = faux_str_deesc(word, len);
  769. faux_str_cat(&result, s);
  770. faux_str_free(s);
  771. }
  772. word = string;
  773. len = 0;
  774. break;
  775. // Escaping
  776. } else if (*string == '\\') {
  777. // Skip escaping
  778. string++;
  779. len++;
  780. // Skip escaped symbol
  781. if (*string) {
  782. string++;
  783. len++;
  784. }
  785. } else {
  786. string++;
  787. len++;
  788. }
  789. }
  790. }
  791. if (len > 0) {
  792. if (alt_quoted) {
  793. faux_str_catn(&result, word, len);
  794. } else {
  795. char *s = faux_str_deesc(word, len);
  796. faux_str_cat(&result, s);
  797. faux_str_free(s);
  798. }
  799. }
  800. if (saveptr)
  801. *saveptr = string;
  802. if (qclosed)
  803. *qclosed = ! (dbl_quoted || alt_quoted);
  804. return result;
  805. }
  806. /** @brief Indicates is string is empty.
  807. *
  808. * @param [in] str String to analyze.
  809. * @return BOOL_TRUE if pointer is NULL or empty, BOOL_FALSE if not empty.
  810. */
  811. bool_t faux_str_is_empty(const char *str)
  812. {
  813. if (!str)
  814. return BOOL_TRUE;
  815. if ('\0' == *str)
  816. return BOOL_TRUE;
  817. return BOOL_FALSE;
  818. }
  819. /** @brief Gets line from multiline string.
  820. *
  821. * @param [in] str String to analyze.
  822. * @param [out] saveptr Pointer to the position after found EOL.
  823. * @return Allocated line or NULL if string is empty.
  824. */
  825. char *faux_str_getline(const char *str, const char **saveptr)
  826. {
  827. const char *find_pos = NULL;
  828. const char *eol = "\n\r";
  829. assert(str);
  830. if (!str)
  831. return NULL;
  832. if ('\0' == *str) {
  833. if (saveptr)
  834. *saveptr = str;
  835. return NULL;
  836. }
  837. find_pos = faux_str_chars(str, eol);
  838. if (find_pos) {
  839. size_t len = find_pos - str;
  840. char *res = NULL;
  841. res = faux_zmalloc(len + 1);
  842. if (len > 0)
  843. memcpy(res, str, len);
  844. if (saveptr)
  845. *saveptr = find_pos + 1;
  846. return res;
  847. }
  848. // Line without EOL
  849. if (saveptr)
  850. *saveptr = str + strlen(str);
  851. return faux_str_dup(str);
  852. }