str.c 25 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055
  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. /** Escape string and add quotes if necessary.
  518. *
  519. * Quotes will be added if string contains spaces.
  520. *
  521. * @warning The returned pointer must be freed by faux_str_free().
  522. * @param [in] src Input string.
  523. * @return Processed string or NULL on error.
  524. */
  525. char *faux_str_c_esc_quote(const char *src)
  526. {
  527. char *space = NULL;
  528. char *escaped = NULL;
  529. char *result = NULL;
  530. if (!src)
  531. return NULL;
  532. escaped = faux_str_c_esc(src);
  533. // String with space must have quotes
  534. space = strchr(escaped, ' ');
  535. if (space) {
  536. result = faux_str_sprintf("\"%s\"", escaped);
  537. faux_str_free(escaped);
  538. } else {
  539. result = escaped;
  540. }
  541. return result;
  542. }
  543. #define BYTE_CONV_LEN 4 // Length of one byte converted to string
  544. /** Prepare binary block for embedding to C-code.
  545. *
  546. * @warning The returned pointer must be freed by faux_str_free().
  547. * @param [in] src Binary block for conversion.
  548. * @return C-string or NULL on error.
  549. */
  550. char *faux_str_c_bin(const char *src, size_t n)
  551. {
  552. const char *src_ptr = src;
  553. char *dst = NULL;
  554. char *dst_ptr = NULL;
  555. size_t dst_len = 0;
  556. if (!src)
  557. return NULL;
  558. // Calculate destination string size.
  559. // Each src character will be replaced by
  560. // something like '\xff'. So it's 4 dst chars for 1 src char.
  561. dst_len = (n * BYTE_CONV_LEN) + 1; // one byte for '\0'
  562. dst = faux_zmalloc(dst_len);
  563. assert(dst);
  564. if (!dst)
  565. return NULL;
  566. dst_ptr = dst;
  567. while (src_ptr < (src + n)) {
  568. char buf[BYTE_CONV_LEN + 1]; // longest 'char' (4 bytes) + '\0'
  569. snprintf(buf, sizeof(buf), "\\x%02x", (unsigned char)*src_ptr);
  570. memcpy(dst_ptr, buf, BYTE_CONV_LEN); // zmalloc() nullify the rest
  571. dst_ptr += BYTE_CONV_LEN;
  572. src_ptr++;
  573. }
  574. return dst;
  575. }
  576. /** @brief Search the n-th chars of string for one of the specified chars.
  577. *
  578. * The function search for any of specified characters within string.
  579. * The search is limited to first n characters of the string. If
  580. * terminating '\0' is before n-th character then search will stop on
  581. * it. Can be used with raw memory block.
  582. *
  583. * @param [in] str String (or memory block) to search in.
  584. * @param [in] chars_to_string Chars enumeration to search for.
  585. * @param [in] n Maximum number of bytes to search within.
  586. * @return Pointer to the first occurence of one of specified chars.
  587. * NULL on error.
  588. */
  589. char *faux_str_charsn(const char *str, const char *chars_to_search, size_t n)
  590. {
  591. const char *current_char = str;
  592. size_t len = n;
  593. if (!str || !chars_to_search)
  594. return NULL;
  595. while ((len > 0) && (*current_char != '\0')) {
  596. if (strchr(chars_to_search, *current_char))
  597. return (char *)current_char;
  598. current_char++;
  599. len--;
  600. }
  601. return NULL;
  602. }
  603. /** @brief Search string for one of the specified chars.
  604. *
  605. * The function search for any of specified characters within string.
  606. *
  607. * @param [in] str String to search in.
  608. * @param [in] chars_to_string Chars enumeration to search for.
  609. * @return Pointer to the first occurence of one of specified chars.
  610. * NULL on error.
  611. */
  612. char *faux_str_chars(const char *str, const char *chars_to_search)
  613. {
  614. if (!str)
  615. return NULL;
  616. return faux_str_charsn(str, chars_to_search, strlen(str));
  617. }
  618. /** @brief Remove escaping. Convert string to internal view.
  619. *
  620. * Find backslashes (before escaped symbols) and remove it. Escaped symbol
  621. * will not be analyzed so `\\` will lead to `\`.
  622. *
  623. * @param [in] string Escaped string.
  624. * @param [in] len Length of string to de-escape.
  625. * @return Allocated de-escaped string
  626. * @warning Returned value must be freed by faux_str_free() later.
  627. */
  628. static char *faux_str_deesc(const char *string, size_t len)
  629. {
  630. const char *s = string;
  631. char *res = NULL;
  632. char *p = NULL;
  633. bool_t escaped = BOOL_FALSE;
  634. if (!string)
  635. return NULL;
  636. if (0 == len)
  637. return NULL;
  638. res = faux_zmalloc(len + 1);
  639. assert(res);
  640. if (!res)
  641. return NULL;
  642. p = res;
  643. while ((*s != '\0') && (s < (string +len))) {
  644. if (('\\' == *s) && !escaped) {
  645. escaped = BOOL_TRUE;
  646. s++;
  647. continue;
  648. }
  649. escaped = BOOL_FALSE;
  650. *p = *s;
  651. s++;
  652. p++;
  653. }
  654. *p = '\0';
  655. return res;
  656. }
  657. /*--------------------------------------------------------- */
  658. /** @brief Find next word or quoted substring within string
  659. *
  660. * The quotation can be of several different kinds.
  661. *
  662. * The first kind is standard double quoting. In this case the internal (within
  663. * quotation) `"` and `\` symbols must be escaped. But symbols will be deescaped
  664. * before writing to internal buffers.
  665. *
  666. * The second kind of quotation is alternative quotation. Any symbol can become
  667. * quote sign. For example "`" and "'" can be considered as a quotes. To use
  668. * some symbols as a quote them must be specified by `alt_quotes` function
  669. * parameter. The single symbol can be considered as a start of quotation or
  670. * a sequence of the same symbols can be considered as a start of quotation. In
  671. * this case the end of quotation is a sequence of the same symbols. The same
  672. * symbol can appear inside quotation but number of symbols (sequence) must be
  673. * less than opening quote sequence. The example of alternatively quoted string
  674. * is ```some text``and anothe`r```. The backslash has no special meaning inside
  675. * quoted string.
  676. *
  677. * The substring can be unquoted string without spaces. The space, backslash and
  678. * quote can be escaped by backslash.
  679. *
  680. * Parts of text with different quotes can be glued together to get single
  681. * substring like this: aaa"inside dbl quote"bbb``alt quote"`here``ccc.
  682. *
  683. * @param [in] str String to parse.
  684. * @param [out] saveptr Pointer to first symbol after found substring.
  685. * @param [in] alt_quotes Possible alternative quotes.
  686. * @param [out] qclosed Flag is quote closed.
  687. * @return Allocated buffer with found substring (without quotes).
  688. * @warning Returned alocated buffer must be freed later by faux_str_free()
  689. */
  690. char *faux_str_nextword(const char *str, const char **saveptr,
  691. const char *alt_quotes, bool_t *qclosed)
  692. {
  693. const char *string = str;
  694. const char *word = NULL;
  695. size_t len = 0;
  696. const char dbl_quote = '"';
  697. bool_t dbl_quoted = BOOL_FALSE;
  698. char alt_quote = '\0';
  699. unsigned int alt_quote_num = 0; // Number of opening alt quotes
  700. bool_t alt_quoted = BOOL_FALSE;
  701. char *result = NULL;
  702. // Find the start of a word (not including an opening quote)
  703. while (*string && isspace(*string))
  704. string++;
  705. word = string; // Suppose not quoted string
  706. while (*string != '\0') {
  707. // Standard double quotation
  708. if (dbl_quoted) {
  709. // End of word
  710. if (*string == dbl_quote) {
  711. if (len > 0) {
  712. char *s = faux_str_deesc(word, len);
  713. faux_str_cat(&result, s);
  714. faux_str_free(s);
  715. }
  716. dbl_quoted = BOOL_FALSE;
  717. string++;
  718. word = string;
  719. len = 0;
  720. // Escaping
  721. } else if (*string == '\\') {
  722. // Skip escaping
  723. string++;
  724. len++;
  725. // Skip escaped symbol
  726. if (*string) {
  727. string++;
  728. len++;
  729. }
  730. } else {
  731. string++;
  732. len++;
  733. }
  734. // Alternative multi quotation
  735. } else if (alt_quoted) {
  736. unsigned int qnum = alt_quote_num;
  737. while (string && (*string == alt_quote) && qnum) {
  738. string++;
  739. len++;
  740. qnum--;
  741. }
  742. if (0 == qnum) { // End of word was found
  743. // Quotes themselfs are not a part of a word
  744. len -= alt_quote_num;
  745. if (len > 0)
  746. faux_str_catn(&result, word, len);
  747. alt_quoted = BOOL_FALSE;
  748. word = string;
  749. len = 0;
  750. } else if (qnum == alt_quote_num) { // No quote syms
  751. string++;
  752. len++;
  753. }
  754. // Not quoted
  755. } else {
  756. // Start of a double quoted string
  757. if (*string == dbl_quote) {
  758. if (len > 0) {
  759. char *s = faux_str_deesc(word, len);
  760. faux_str_cat(&result, s);
  761. faux_str_free(s);
  762. }
  763. dbl_quoted = BOOL_TRUE;
  764. string++;
  765. word = string;
  766. len = 0;
  767. // Start of alt quoted string
  768. } else if (alt_quotes && strchr(alt_quotes, *string)) {
  769. if (len > 0) {
  770. char *s = faux_str_deesc(word, len);
  771. faux_str_cat(&result, s);
  772. faux_str_free(s);
  773. }
  774. alt_quoted = BOOL_TRUE;
  775. alt_quote = *string;
  776. alt_quote_num = 0;
  777. while (string && (*string == alt_quote)) {
  778. string++;
  779. alt_quote_num++; // Count starting quotes
  780. }
  781. word = string;
  782. len = 0;
  783. // End of word
  784. } else if (isspace(*string)) {
  785. if (len > 0) {
  786. char *s = faux_str_deesc(word, len);
  787. faux_str_cat(&result, s);
  788. faux_str_free(s);
  789. }
  790. word = string;
  791. len = 0;
  792. break;
  793. // Escaping
  794. } else if (*string == '\\') {
  795. // Skip escaping
  796. string++;
  797. len++;
  798. // Skip escaped symbol
  799. if (*string) {
  800. string++;
  801. len++;
  802. }
  803. } else {
  804. string++;
  805. len++;
  806. }
  807. }
  808. }
  809. if (len > 0) {
  810. if (alt_quoted) {
  811. faux_str_catn(&result, word, len);
  812. } else {
  813. char *s = faux_str_deesc(word, len);
  814. faux_str_cat(&result, s);
  815. faux_str_free(s);
  816. }
  817. }
  818. if (saveptr)
  819. *saveptr = string;
  820. if (qclosed)
  821. *qclosed = ! (dbl_quoted || alt_quoted);
  822. return result;
  823. }
  824. /** @brief Indicates is string is empty.
  825. *
  826. * @param [in] str String to analyze.
  827. * @return BOOL_TRUE if pointer is NULL or empty, BOOL_FALSE if not empty.
  828. */
  829. bool_t faux_str_is_empty(const char *str)
  830. {
  831. if (!str)
  832. return BOOL_TRUE;
  833. if ('\0' == *str)
  834. return BOOL_TRUE;
  835. return BOOL_FALSE;
  836. }
  837. /** @brief Gets line from multiline string.
  838. *
  839. * @param [in] str String to analyze.
  840. * @param [out] saveptr Pointer to the position after found EOL.
  841. * @return Allocated line or NULL if string is empty.
  842. */
  843. char *faux_str_getline(const char *str, const char **saveptr)
  844. {
  845. const char *find_pos = NULL;
  846. const char *eol = "\n\r";
  847. if (!str)
  848. return NULL;
  849. if ('\0' == *str) {
  850. if (saveptr)
  851. *saveptr = str;
  852. return NULL;
  853. }
  854. find_pos = faux_str_chars(str, eol);
  855. if (find_pos) {
  856. size_t len = find_pos - str;
  857. char *res = NULL;
  858. res = faux_zmalloc(len + 1);
  859. if (len > 0)
  860. memcpy(res, str, len);
  861. if (saveptr)
  862. *saveptr = find_pos + 1;
  863. return res;
  864. }
  865. // Line without EOL
  866. if (saveptr)
  867. *saveptr = str + strlen(str);
  868. return faux_str_dup(str);
  869. }
  870. /** @brief Indicates if string has unclosed quotes.
  871. *
  872. * @param [in] str String to analyze.
  873. * @return BOOL_TRUE if string has unclosed quotes, BOOL_FALSE if doesn't.
  874. */
  875. bool_t faux_str_unclosed_quotes(const char *str, const char *alt_quotes)
  876. {
  877. const char *saveptr = str;
  878. char *word = NULL;
  879. if (faux_str_is_empty(str))
  880. return BOOL_FALSE;
  881. do {
  882. bool_t closed_quotes = BOOL_TRUE;
  883. word = faux_str_nextword(saveptr, &saveptr, alt_quotes, &closed_quotes);
  884. faux_str_free(word);
  885. if (!closed_quotes)
  886. return BOOL_TRUE;
  887. } while (word);
  888. return BOOL_FALSE;
  889. }
  890. /** @brief Indicates is string has content.
  891. *
  892. * Empty string has no content. String contains only spaces is considered
  893. * doesn't have content too.
  894. *
  895. * @param [in] str String to analyze.
  896. * @return BOOL_TRUE if string has content, BOOL_FALSE if doesn't.
  897. */
  898. bool_t faux_str_has_content(const char *str)
  899. {
  900. const char *l = str;
  901. if (faux_str_is_empty(l))
  902. return BOOL_FALSE;
  903. while (*l) {
  904. if (!isspace(*l))
  905. return BOOL_TRUE;
  906. l++;
  907. }
  908. return BOOL_FALSE;
  909. }