str.c 25 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024
  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. }
  844. /** @brief Indicates if string has unclosed quotes.
  845. *
  846. * @param [in] str String to analyze.
  847. * @return BOOL_TRUE if string has unclosed quotes, BOOL_FALSE if doesn't.
  848. */
  849. bool_t faux_str_unclosed_quotes(const char *str, const char *alt_quotes)
  850. {
  851. const char *saveptr = str;
  852. char *word = NULL;
  853. if (faux_str_is_empty(str))
  854. return BOOL_FALSE;
  855. do {
  856. bool_t closed_quotes = BOOL_TRUE;
  857. word = faux_str_nextword(saveptr, &saveptr, alt_quotes, &closed_quotes);
  858. faux_str_free(word);
  859. if (!closed_quotes)
  860. return BOOL_TRUE;
  861. } while (word);
  862. return BOOL_FALSE;
  863. }
  864. /** @brief Indicates is string has content.
  865. *
  866. * Empty string has no content. String contains only spaces is considered
  867. * doesn't have content too.
  868. *
  869. * @param [in] str String to analyze.
  870. * @return BOOL_TRUE if string has content, BOOL_FALSE if doesn't.
  871. */
  872. bool_t faux_str_has_content(const char *str)
  873. {
  874. const char *l = str;
  875. if (faux_str_is_empty(l))
  876. return BOOL_FALSE;
  877. while (*l) {
  878. if (!isspace(*l))
  879. return BOOL_TRUE;
  880. l++;
  881. }
  882. return BOOL_FALSE;
  883. }