string_misc.h 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. #include <string.h>
  2. #include <stdlib.h>
  3. #include <stddef.h>
  4. #ifndef STRING_MISC_H
  5. #define STRING_MISC_H
  6. #if (__STDC_VERSION__ >= 199901L)
  7. #include <stdint.h>
  8. #endif
  9. char *repl_str(const char *str, const char *from, const char *to) {
  10. /* Adjust each of the below values to suit your needs. */
  11. /* Increment positions cache size initially by this number. */
  12. size_t cache_sz_inc = 16;
  13. /* Thereafter, each time capacity needs to be increased,
  14. * multiply the increment by this factor. */
  15. const size_t cache_sz_inc_factor = 3;
  16. /* But never increment capacity by more than this number. */
  17. const size_t cache_sz_inc_max = 1048576;
  18. char *pret, *ret = NULL;
  19. const char *pstr2, *pstr = str;
  20. size_t i, count = 0;
  21. #if (__STDC_VERSION__ >= 199901L)
  22. uintptr_t *pos_cache_tmp, *pos_cache = NULL;
  23. #else
  24. ptrdiff_t *pos_cache_tmp, *pos_cache = NULL;
  25. #endif
  26. size_t cache_sz = 0;
  27. size_t cpylen, orglen, retlen, tolen, fromlen = strlen(from);
  28. /* Find all matches and cache their positions. */
  29. while ((pstr2 = strstr(pstr, from)) != NULL) {
  30. count++;
  31. /* Increase the cache size when necessary. */
  32. if (cache_sz < count) {
  33. cache_sz += cache_sz_inc;
  34. pos_cache_tmp = realloc(pos_cache, sizeof(*pos_cache) * cache_sz);
  35. if (pos_cache_tmp == NULL) {
  36. goto end_repl_str;
  37. } else pos_cache = pos_cache_tmp;
  38. cache_sz_inc *= cache_sz_inc_factor;
  39. if (cache_sz_inc > cache_sz_inc_max) {
  40. cache_sz_inc = cache_sz_inc_max;
  41. }
  42. }
  43. pos_cache[count-1] = pstr2 - str;
  44. pstr = pstr2 + fromlen;
  45. }
  46. orglen = pstr - str + strlen(pstr);
  47. /* Allocate memory for the post-replacement string. */
  48. if (count > 0) {
  49. tolen = strlen(to);
  50. retlen = orglen + (tolen - fromlen) * count;
  51. } else retlen = orglen;
  52. ret = malloc(retlen + 1);
  53. if (ret == NULL) {
  54. goto end_repl_str;
  55. }
  56. if (count == 0) {
  57. /* If no matches, then just duplicate the string. */
  58. strcpy(ret, str);
  59. } else {
  60. /* Otherwise, duplicate the string whilst performing
  61. * the replacements using the position cache. */
  62. pret = ret;
  63. memcpy(pret, str, pos_cache[0]);
  64. pret += pos_cache[0];
  65. for (i = 0; i < count; i++) {
  66. memcpy(pret, to, tolen);
  67. pret += tolen;
  68. pstr = str + pos_cache[i] + fromlen;
  69. cpylen = (i == count-1 ? orglen : pos_cache[i+1]) - pos_cache[i] - fromlen;
  70. memcpy(pret, pstr, cpylen);
  71. pret += cpylen;
  72. }
  73. ret[retlen] = '\0';
  74. }
  75. end_repl_str:
  76. /* Free the cache and return the post-replacement string,
  77. * which will be NULL in the event of an error. */
  78. free(pos_cache);
  79. return ret;
  80. }
  81. #endif