str.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  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 "faux/ctype.h"
  11. #include "faux/str.h"
  12. /* TODO: Are that vars really needed? */
  13. //const char *lub_string_esc_default = "`|$<>&()#;\\\"!";
  14. //const char *lub_string_esc_regex = "^$.*+[](){}";
  15. //const char *lub_string_esc_quoted = "\\\"";
  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. if (str)
  26. 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. if (!str)
  40. return NULL;
  41. return strdup(str);
  42. }
  43. /** @brief Duplicates the first n bytes of the string.
  44. *
  45. * Duplicates at most n bytes of the string. Allocates
  46. * memory with malloc(). Checks for NULL pointer. Function will allocate
  47. * n + 1 bytes to store string and terminating null byte.
  48. *
  49. * @warning Resulting string must be freed by faux_str_free().
  50. *
  51. * @param [in] str String to duplicate.
  52. * @param [in] n Number of bytes to copy.
  53. * @return Pointer to allocated string or NULL.
  54. */
  55. char *faux_str_dupn(const char *str, size_t n) {
  56. char *res = NULL;
  57. size_t len = 0;
  58. if (!str)
  59. return NULL;
  60. len = strlen(str);
  61. len = (len < n) ? len : n;
  62. res = malloc(len + 1);
  63. if (!res)
  64. return NULL;
  65. strncpy(res, str, len);
  66. res[len] = '\0';
  67. return res;
  68. }
  69. /** @brief Generates lowercase copy of input string.
  70. *
  71. * Allocates the copy of input string and convert that copy to lowercase.
  72. *
  73. * @warning Resulting string must be freed by faux_str_free().
  74. *
  75. * @param [in] str String to convert.
  76. * @return Pointer to lowercase string copy or NULL.
  77. */
  78. char *faux_str_tolower(const char *str)
  79. {
  80. char *res = faux_str_dup(str);
  81. char *p = res;
  82. if (!res)
  83. return NULL;
  84. while (*p) {
  85. *p = faux_ctype_tolower(*p);
  86. p++;
  87. }
  88. return res;
  89. }
  90. /** @brief Generates uppercase copy of input string.
  91. *
  92. * Allocates the copy of input string and convert that copy to uppercase.
  93. *
  94. * @warning Resulting string must be freed by faux_str_free().
  95. *
  96. * @param [in] str String to convert.
  97. * @return Pointer to lowercase string copy or NULL.
  98. */
  99. char *faux_str_toupper(const char *str)
  100. {
  101. char *res = faux_str_dup(str);
  102. char *p = res;
  103. if (!res)
  104. return NULL;
  105. while (*p) {
  106. *p = faux_ctype_toupper(*p);
  107. p++;
  108. }
  109. return res;
  110. }
  111. /** @brief Add n bytes of text to existent string.
  112. *
  113. * Concatenate two strings. Add n bytes of second string to the end of the
  114. * first one. The first argument is address of string pointer. The pointer
  115. * can be changed due to realloc() features. The first pointer can be NULL.
  116. * In this case the memory will be malloc()-ed and stored to the first pointer.
  117. *
  118. * @param [in,out] str Address of first string pointer.
  119. * @param [in] text Text to add to the first string.
  120. * @param [in] n Number of bytes to add.
  121. * @return Pointer to resulting string or NULL.
  122. */
  123. char *faux_str_catn(char **str, const char *text, size_t n) {
  124. size_t str_len = 0;
  125. size_t text_len = 0;
  126. char *res = NULL;
  127. char *p = NULL;
  128. if (!text)
  129. return *str;
  130. str_len = (*str) ? strlen(*str) : 0;
  131. text_len = strlen(text);
  132. text_len = (text_len < n) ? text_len : n;
  133. res = realloc(*str, str_len + text_len + 1);
  134. if (!res)
  135. return NULL;
  136. p = res + str_len;
  137. strncpy(p, text, text_len);
  138. p[text_len] = '\0';
  139. *str = res;
  140. return res;
  141. }
  142. /** @brief Add some text to existent string.
  143. *
  144. * Concatenate two strings. Add second string to the end of the first one.
  145. * The first argument is address of string pointer. The pointer can be
  146. * changed due to realloc() features. The first pointer can be NULL. In this
  147. * case the memory will be malloc()-ed and stored to the first pointer.
  148. *
  149. * @param [in,out] str Address of first string pointer.
  150. * @param [in] text Text to add to the first string.
  151. * @return Pointer to resulting string or NULL.
  152. */
  153. char *faux_str_cat(char **str, const char *text) {
  154. size_t len = 0;
  155. if (!text)
  156. return *str;
  157. len = strlen(text);
  158. return faux_str_catn(str, text, len);
  159. }
  160. /** @brief Compare n first characters of two strings ignoring case.
  161. *
  162. * The difference beetween this function an standard strncasecmp() is
  163. * faux function uses faux ctype functions. It can be important for
  164. * portability.
  165. *
  166. * @param [in] str1 First string to compare.
  167. * @param [in] str2 Second string to compare.
  168. * @param [in] n Number of characters to compare.
  169. * @return < 0, 0, > 0, see the strcasecmp().
  170. */
  171. int faux_str_ncasecmp(const char *str1, const char *str2, size_t n) {
  172. const char *p1 = str1;
  173. const char *p2 = str2;
  174. size_t num = n;
  175. while ((*p1 || *p2) && num) {
  176. int res = 0;
  177. char c1 = faux_ctype_tolower(*p1);
  178. char c2 = faux_ctype_tolower(*p2);
  179. res = c1 - c2;
  180. if (res)
  181. return res;
  182. p1++;
  183. p2++;
  184. num--;
  185. }
  186. return 0;
  187. }
  188. /** @brief Compare two strings ignoring case.
  189. *
  190. * The difference beetween this function an standard strcasecmp() is
  191. * faux function uses faux ctype functions. It can be important for
  192. * portability.
  193. *
  194. * @param [in] str1 First string to compare.
  195. * @param [in] str2 Second string to compare.
  196. * @return < 0, 0, > 0, see the strcasecmp().
  197. */
  198. int faux_str_casecmp(const char *str1, const char *str2) {
  199. const char *p1 = str1;
  200. const char *p2 = str2;
  201. while (*p1 || *p2) {
  202. int res = 0;
  203. char c1 = faux_ctype_tolower(*p1);
  204. char c2 = faux_ctype_tolower(*p2);
  205. res = c1 - c2;
  206. if (res)
  207. return res;
  208. p1++;
  209. p2++;
  210. }
  211. return 0;
  212. }
  213. const char *lub_string_nocasestr(const char *cs, const char *ct)
  214. {
  215. const char *p = NULL;
  216. const char *result = NULL;
  217. while (*cs) {
  218. const char *q = cs;
  219. p = ct;
  220. while (*p && *q
  221. && (faux_ctype_tolower(*p) == faux_ctype_tolower(*q))) {
  222. p++, q++;
  223. }
  224. if (0 == *p) {
  225. break;
  226. }
  227. cs++;
  228. }
  229. if (p && !*p) {
  230. result = cs;
  231. }
  232. return result;
  233. }
  234. // TODO: Is it needed?
  235. /*
  236. char *lub_string_ndecode(const char *string, unsigned int len)
  237. {
  238. const char *s = string;
  239. char *res, *p;
  240. int esc = 0;
  241. if (!string)
  242. return NULL;
  243. p = res = malloc(len + 1);
  244. while (*s && (s < (string +len))) {
  245. if (!esc) {
  246. if ('\\' == *s)
  247. esc = 1;
  248. else
  249. *p = *s;
  250. } else {
  251. // switch (*s) {
  252. // case 'r':
  253. // case 'n':
  254. // *p = '\n';
  255. // break;
  256. // case 't':
  257. // *p = '\t';
  258. // break;
  259. // default:
  260. // *p = *s;
  261. // break;
  262. // }
  263. // *p = *s;
  264. esc = 0;
  265. }
  266. if (!esc)
  267. p++;
  268. s++;
  269. }
  270. *p = '\0';
  271. return res;
  272. }
  273. */
  274. // TODO: Is it needed?
  275. /*
  276. inline char *lub_string_decode(const char *string)
  277. {
  278. return lub_string_ndecode(string, strlen(string));
  279. }
  280. */
  281. // TODO: Is it needed?
  282. /*----------------------------------------------------------- */
  283. /*
  284. * This needs to escape any dangerous characters within the command line
  285. * to prevent gaining access to the underlying system shell.
  286. */
  287. /*
  288. char *lub_string_encode(const char *string, const char *escape_chars)
  289. {
  290. char *result = NULL;
  291. const char *p;
  292. if (!escape_chars)
  293. return lub_string_dup(string);
  294. if (string && !(*string)) // Empty string
  295. return lub_string_dup(string);
  296. for (p = string; p && *p; p++) {
  297. // find any special characters and prefix them with '\'
  298. size_t len = strcspn(p, escape_chars);
  299. lub_string_catn(&result, p, len);
  300. p += len;
  301. if (*p) {
  302. lub_string_catn(&result, "\\", 1);
  303. lub_string_catn(&result, p, 1);
  304. } else {
  305. break;
  306. }
  307. }
  308. return result;
  309. }
  310. */
  311. // TODO: Is it needed?
  312. /*--------------------------------------------------------- */
  313. /*
  314. unsigned int lub_string_equal_part(const char *str1, const char *str2,
  315. bool_t utf8)
  316. {
  317. unsigned int cnt = 0;
  318. if (!str1 || !str2)
  319. return cnt;
  320. while (*str1 && *str2) {
  321. if (*str1 != *str2)
  322. break;
  323. cnt++;
  324. str1++;
  325. str2++;
  326. }
  327. if (!utf8)
  328. return cnt;
  329. // UTF8 features
  330. if (cnt && (UTF8_11 == (*(str1 - 1) & UTF8_MASK)))
  331. cnt--;
  332. return cnt;
  333. }
  334. */
  335. // TODO: Is it needed?
  336. /*--------------------------------------------------------- */
  337. /*
  338. const char *lub_string_suffix(const char *string)
  339. {
  340. const char *p1, *p2;
  341. p1 = p2 = string;
  342. while (*p1) {
  343. if (faux_ctype_isspace(*p1)) {
  344. p2 = p1;
  345. p2++;
  346. }
  347. p1++;
  348. }
  349. return p2;
  350. }
  351. */
  352. // TODO: Is it needed?
  353. /*--------------------------------------------------------- */
  354. /*
  355. const char *lub_string_nextword(const char *string,
  356. size_t *len, size_t *offset, size_t *quoted)
  357. {
  358. const char *word;
  359. *quoted = 0;
  360. // Find the start of a word (not including an opening quote)
  361. while (*string && isspace(*string)) {
  362. string++;
  363. (*offset)++;
  364. }
  365. // Is this the start of a quoted string ?
  366. if (*string == '"') {
  367. *quoted = 1;
  368. string++;
  369. }
  370. word = string;
  371. *len = 0;
  372. // Find the end of the word
  373. while (*string) {
  374. if (*string == '\\') {
  375. string++;
  376. (*len)++;
  377. if (*string) {
  378. (*len)++;
  379. string++;
  380. }
  381. continue;
  382. }
  383. // End of word
  384. if (!*quoted && isspace(*string))
  385. break;
  386. if (*string == '"') {
  387. // End of a quoted string
  388. *quoted = 2;
  389. break;
  390. }
  391. (*len)++;
  392. string++;
  393. }
  394. return word;
  395. }
  396. */
  397. // TODO: Is it needed?
  398. /*--------------------------------------------------------- */
  399. /*
  400. unsigned int lub_string_wordcount(const char *line)
  401. {
  402. const char *word;
  403. unsigned int result = 0;
  404. size_t len = 0, offset = 0;
  405. size_t quoted;
  406. for (word = lub_string_nextword(line, &len, &offset, &quoted);
  407. *word || quoted;
  408. word = lub_string_nextword(word + len, &len, &offset, &quoted)) {
  409. // account for the terminating quotation mark
  410. len += quoted ? quoted - 1 : 0;
  411. result++;
  412. }
  413. return result;
  414. }
  415. */