iron_string.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. #include "iron_string.h"
  2. #include <ctype.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. void *gc_alloc(size_t size);
  7. void gc_leaf(void *ptr);
  8. char *string_alloc(int size) {
  9. char *r = gc_alloc(size);
  10. gc_leaf(r);
  11. return r;
  12. }
  13. char *string_join(char *a, char *b) {
  14. char *r = string_alloc(strlen(a) + strlen(b) + 1);
  15. strcpy(r, a);
  16. strcat(r, b);
  17. return r;
  18. }
  19. char *string_copy(char *a) {
  20. if (a == NULL) {
  21. return NULL;
  22. }
  23. char *r = string_alloc(strlen(a) + 1);
  24. strcpy(r, a);
  25. return r;
  26. }
  27. int string_length(char *str) {
  28. return strlen(str);
  29. }
  30. bool string_equals(char *a, char *b) {
  31. if (a == NULL || b == NULL) {
  32. return false;
  33. }
  34. return strcmp(a, b) == 0;
  35. }
  36. char *i32_to_string(int32_t i) {
  37. int l = snprintf(NULL, 0, "%d", i);
  38. char *r = string_alloc(l + 1);
  39. sprintf(r, "%d", i);
  40. return r;
  41. }
  42. char *i32_to_string_hex(int32_t i) {
  43. int l = snprintf(NULL, 0, "%X", i);
  44. char *r = string_alloc(l + 1);
  45. sprintf(r, "%X", i);
  46. return r;
  47. }
  48. #ifdef IRON_WINDOWS
  49. #define PERCENT_LD "%lld"
  50. #define PERCENT_LU "%llu"
  51. #else
  52. #define PERCENT_LD "%ld"
  53. #define PERCENT_LU "%lu"
  54. #endif
  55. char *i64_to_string(int64_t i) {
  56. int l = snprintf(NULL, 0, PERCENT_LD, i);
  57. char *r = string_alloc(l + 1);
  58. sprintf(r, PERCENT_LD, i);
  59. return r;
  60. }
  61. char *u64_to_string(uint64_t i) {
  62. int l = snprintf(NULL, 0, PERCENT_LU, i);
  63. char *r = string_alloc(l + 1);
  64. sprintf(r, PERCENT_LU, i);
  65. return r;
  66. }
  67. char *f32_to_string_with_zeros(float f) {
  68. int l = snprintf(NULL, 0, "%f", f);
  69. char *r = string_alloc(l + 1);
  70. sprintf(r, "%f", f);
  71. return r;
  72. }
  73. char *f32_to_string(float f) {
  74. char *r = f32_to_string_with_zeros(f);
  75. string_strip_trailing_zeros(r);
  76. return r;
  77. }
  78. void string_strip_trailing_zeros(char *str) {
  79. int len = strlen(str);
  80. while (str[--len] == '0') {
  81. str[len] = '\0';
  82. }
  83. if (str[len] == '.') {
  84. str[len] = '\0';
  85. }
  86. }
  87. int32_t string_index_of_pos(char *s, char *search, int pos) {
  88. char *found = strstr(s + pos, search);
  89. if (found != NULL) {
  90. return found - s;
  91. }
  92. return -1;
  93. }
  94. int32_t string_index_of(char *s, char *search) {
  95. return string_index_of_pos(s, search, 0);
  96. }
  97. int32_t string_last_index_of(char *str, char *search) {
  98. char *s = str;
  99. char *found = NULL;
  100. while (1) {
  101. char *p = strstr(s, search);
  102. if (p == NULL) {
  103. break;
  104. }
  105. found = p;
  106. s = p + 1;
  107. }
  108. if (found != NULL) {
  109. return found - str;
  110. }
  111. return -1;
  112. }
  113. any_array_t *string_split(char *s, char *sep) {
  114. any_array_t *a = gc_alloc(sizeof(any_array_t));
  115. int sep_len = strlen(sep);
  116. char *pos = s;
  117. while (true) {
  118. char *next = strstr(pos, sep);
  119. if (next == NULL) {
  120. any_array_push(a, string_copy(pos));
  121. break;
  122. }
  123. int part_len = next - pos;
  124. char *part = string_alloc(part_len + 1);
  125. strncpy(part, pos, part_len);
  126. part[part_len] = '\0';
  127. any_array_push(a, part);
  128. pos = next + sep_len;
  129. }
  130. return a;
  131. }
  132. char *string_array_join(any_array_t *a, char *separator) {
  133. int len = 0;
  134. int len_sep = strlen(separator);
  135. for (int i = 0; i < a->length; ++i) {
  136. len += strlen(a->buffer[i]);
  137. if (i < a->length - 1) {
  138. len += len_sep;
  139. }
  140. }
  141. char *r = string_alloc(len + 1);
  142. for (int i = 0; i < a->length; ++i) {
  143. strcat(r, a->buffer[i]);
  144. if (i < a->length - 1) {
  145. strcat(r, separator);
  146. }
  147. }
  148. return r;
  149. }
  150. char *string_replace_all(char *s, char *search, char *replace) {
  151. char *buffer = string_alloc(1024);
  152. char *buffer_pos = buffer;
  153. size_t search_len = strlen(search);
  154. size_t replace_len = strlen(replace);
  155. while (1) {
  156. char *p = strstr(s, search);
  157. if (p == NULL) {
  158. strcpy(buffer_pos, s);
  159. break;
  160. }
  161. memcpy(buffer_pos, s, p - s);
  162. buffer_pos += p - s;
  163. memcpy(buffer_pos, replace, replace_len);
  164. buffer_pos += replace_len;
  165. s = p + search_len;
  166. }
  167. return buffer;
  168. }
  169. char *substring(char *s, int32_t start, int32_t end) {
  170. char *buffer = string_alloc(end - start + 1);
  171. for (int i = 0; i < end - start; ++i) {
  172. buffer[i] = s[start + i];
  173. }
  174. return buffer;
  175. }
  176. char *string_from_char_code(int32_t c) {
  177. char *r = string_alloc(2);
  178. r[0] = c;
  179. r[1] = '\0';
  180. return r;
  181. }
  182. int32_t char_code_at(char *s, int32_t i) {
  183. return s[i];
  184. }
  185. char *char_at(char *s, int32_t i) {
  186. char *r = string_alloc(2);
  187. r[0] = s[i];
  188. r[1] = '\0';
  189. return r;
  190. }
  191. bool starts_with(char *s, char *start) {
  192. return strncmp(start, s, strlen(start)) == 0;
  193. }
  194. bool ends_with(char *s, char *end) {
  195. size_t len_s = strlen(s);
  196. size_t len_end = strlen(end);
  197. return strncmp(s + len_s - len_end, end, len_end) == 0;
  198. }
  199. char *to_lower_case(char *s) {
  200. char *r = string_alloc(strlen(s) + 1);
  201. strcpy(r, s);
  202. int len = string_length(r);
  203. for (int i = 0; i < len; ++i) {
  204. r[i] = tolower(r[i]);
  205. }
  206. return r;
  207. }
  208. char *to_upper_case(char *s) {
  209. char *r = string_alloc(strlen(s) + 1);
  210. strcpy(r, s);
  211. int len = string_length(r);
  212. for (int i = 0; i < len; ++i) {
  213. r[i] = toupper(r[i]);
  214. }
  215. return r;
  216. }
  217. char *trim_end(char *str) {
  218. int pos = string_length(str) - 1;
  219. while (pos >= 0 && (str[pos] == ' ' || str[pos] == '\n' || str[pos] == '\r')) {
  220. pos--;
  221. }
  222. return substring(str, 0, pos + 1);
  223. }
  224. // Per Lowgren, CC BY-SA 3.0
  225. // https://stackoverflow.com/a/35332046
  226. #define is_unicode(c) (((c) & 0xc0) == 0xc0)
  227. int string_utf8_decode(const char *str, int *i) {
  228. const unsigned char *s = (const unsigned char *)str;
  229. int u = *s, l = 1;
  230. if (is_unicode(u)) {
  231. int a = (u & 0x20) ? ((u & 0x10) ? ((u & 0x08) ? ((u & 0x04) ? 6 : 5) : 4) : 3) : 2;
  232. if (a < 6 || !(u & 0x02)) {
  233. u = ((u << (a + 1)) & 0xff) >> (a + 1);
  234. for (int b = 1; b < a; ++b)
  235. u = (u << 6) | (s[l++] & 0x3f);
  236. }
  237. }
  238. if (i)
  239. *i += l;
  240. return u;
  241. }