str_list.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. typedef struct strlist {
  2. int len;
  3. int alloc;
  4. char** entries;
  5. } strlist;
  6. #define PP_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, N, ...) N
  7. #define PP_RSEQ_N() 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
  8. #define PP_NARG_(...) PP_ARG_N(__VA_ARGS__)
  9. #define PP_NARG(...) PP_NARG_(__VA_ARGS__, PP_RSEQ_N())
  10. void strlist_init(strlist* sl) {
  11. sl->len = 0;
  12. sl->alloc = 32;
  13. sl->entries = malloc(sl->alloc * sizeof(*sl->entries));
  14. }
  15. strlist* strlist_new() {
  16. strlist* sl = malloc(sizeof(*sl));
  17. strlist_init(sl);
  18. return sl;
  19. }
  20. void strlist_push(strlist* sl, char* e) {
  21. check_alloc(sl);
  22. sl->entries[sl->len++] = e;
  23. }
  24. typedef unsigned long hash_t;
  25. hash_t strhash(char* str) {
  26. unsigned long h = 0;
  27. int c;
  28. while(c = *str++) {
  29. h = c + (h << 6) + (h << 16) - h;
  30. }
  31. return h;
  32. }
  33. hash_t strnhash(char* str, size_t n) {
  34. unsigned long h = 0;
  35. int c;
  36. while((c = *str++) && n--) {
  37. h = c + (h << 6) + (h << 16) - h;
  38. }
  39. return h;
  40. }
  41. size_t list_len(char** list) {
  42. size_t total = 0;
  43. for(; *list; list++) total++;
  44. return total;
  45. }
  46. char** concat_lists_(int nargs, ...) {
  47. size_t total = 0;
  48. char** out, **end;
  49. if(nargs == 0) return NULL;
  50. // calculate total list length
  51. va_list va;
  52. va_start(va, nargs);
  53. for(size_t i = 0; i < nargs; i++) {
  54. char** s = va_arg(va, char**);
  55. if(s) total += list_len(s);
  56. }
  57. va_end(va);
  58. out = malloc((total + 1) * sizeof(char**));
  59. end = out;
  60. va_start(va, nargs);
  61. // concat lists
  62. for(size_t i = 0; i < nargs; i++) {
  63. char** s = va_arg(va, char**);
  64. size_t l = list_len(s);
  65. if(s) {
  66. memcpy(end, s, l * sizeof(*s));
  67. end += l;
  68. }
  69. }
  70. va_end(va);
  71. *end = 0;
  72. return out;
  73. }
  74. char* join_str_list(char* list[], char* joiner) {
  75. size_t list_len = 0;
  76. size_t total = 0;
  77. size_t jlen = strlen(joiner);
  78. // calculate total length
  79. for(int i = 0; list[i]; i++) {
  80. list_len++;
  81. total += strlen(list[i]);
  82. }
  83. if(total == 0) return strdup("");
  84. total += (list_len - 1) * jlen;
  85. char* out = malloc((total + 1) * sizeof(*out));
  86. char* end = out;
  87. for(int i = 0; list[i]; i++) {
  88. char* s = list[i];
  89. size_t l = strlen(s);
  90. if(i > 0) {
  91. memcpy(end, joiner, jlen);
  92. end += jlen;
  93. }
  94. if(s) {
  95. memcpy(end, s, l);
  96. end += l;
  97. }
  98. total += strlen(list[i]);
  99. }
  100. *end = 0;
  101. return out;
  102. }
  103. // concatenate all argument strings together in a new buffer
  104. char* strcatdup_(size_t nargs, ...) {
  105. size_t total = 0;
  106. char* out, *end;
  107. if(nargs == 0) return NULL;
  108. // calculate total buffer len
  109. va_list va;
  110. va_start(va, nargs);
  111. for(size_t i = 0; i < nargs; i++) {
  112. char* s = va_arg(va, char*);
  113. if(s) total += strlen(s);
  114. }
  115. va_end(va);
  116. out = malloc((total + 1) * sizeof(char*));
  117. end = out;
  118. va_start(va, nargs);
  119. for(size_t i = 0; i < nargs; i++) {
  120. char* s = va_arg(va, char*);
  121. if(s) {
  122. strcpy(end, s); // not exactly the ost efficient, but maybe faster than
  123. end += strlen(s); // a C version. TODO: test the speed
  124. };
  125. }
  126. va_end(va);
  127. *end = 0;
  128. return out;
  129. }
  130. // concatenate all argument strings together in a new buffer,
  131. // with the given joining string between them
  132. char* strjoin_(char* joiner, size_t nargs, ...) {
  133. size_t total = 0;
  134. char* out, *end;
  135. size_t j_len;
  136. if(nargs == 0) return NULL;
  137. // calculate total buffer len
  138. va_list va;
  139. va_start(va, nargs);
  140. for(size_t i = 0; i < nargs; i++) {
  141. char* s = va_arg(va, char*);
  142. if(s) total += strlen(s);
  143. }
  144. va_end(va);
  145. j_len = strlen(joiner);
  146. total += j_len * (nargs - 1);
  147. out = malloc((total + 1) * sizeof(char*));
  148. end = out;
  149. va_start(va, nargs);
  150. for(size_t i = 0; i < nargs; i++) {
  151. char* s = va_arg(va, char*);
  152. if(s) {
  153. if(i > 0) {
  154. strcpy(end, joiner);
  155. end += j_len;
  156. }
  157. strcpy(end, s); // not exactly the ost efficient, but maybe faster than
  158. end += strlen(s); // a C version. TODO: test the speed
  159. };
  160. }
  161. va_end(va);
  162. *end = 0;
  163. return out;
  164. }
  165. // allocates a new buffer and calls sprintf with it
  166. // why isn't this a standard function?
  167. char* sprintfdup(char* fmt, ...) {
  168. va_list va;
  169. va_start(va, fmt);
  170. size_t n = vsnprintf(NULL, 0, fmt, va);
  171. char* buf = malloc(n + 1);
  172. va_end(va);
  173. va_start(va, fmt);
  174. vsnprintf(buf, n + 1, fmt, va);
  175. va_end(va);
  176. return buf;
  177. }
  178. char** strsplit(char* splitters, char* in, long* out_len) {
  179. char* e;
  180. int alloc = 32;
  181. int len = 0;
  182. char** list = malloc(alloc * sizeof(*list));
  183. for(char* s = in; *s;) {
  184. e = strpbrk(s, splitters);
  185. if(!e) e = s + strlen(s);
  186. if(len >= alloc - 1) {
  187. alloc *= 2;
  188. list = realloc(list, alloc* sizeof(*list));
  189. }
  190. list[len++] = strndup(s, e - s);
  191. e += strspn(e, splitters);
  192. s = e;
  193. }
  194. list[len] = NULL;
  195. if(out_len) *out_len = len;
  196. return list;
  197. }
  198. char** read_split_file(char* path, char* sep, long* out_len) {
  199. int fd;
  200. struct stat st;
  201. char* contents;
  202. fd = open(path, O_RDONLY);
  203. if (fd == -1) {
  204. fprintf(stderr, "Could not open file '%s'.\n", path);
  205. return NULL;
  206. }
  207. fstat(fd, &st);
  208. contents = mmap(NULL, st.st_size + 1, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
  209. if(contents == MAP_FAILED) {
  210. fprintf(stderr, "Failed to map anonymous memory region of size %d\n", st.st_size + 1);
  211. }
  212. contents = mmap(contents, st.st_size, PROT_READ, MAP_SHARED | MAP_FIXED | MAP_POPULATE, fd, 0);
  213. if(contents == MAP_FAILED) {
  214. fprintf(stderr, "Failed to map file into memory: '%s'\n", argv[1]);
  215. }
  216. char** out = strsplit(sep, contents, out_len);
  217. munmap(contents, st.st_size);
  218. close(fd);
  219. return out;
  220. }