str.c (2799B)
1 #define _ISOC99_SOURCE /* vsnprintf */ 2 #include <errno.h> 3 #include <stdio.h> 4 #include <string.h> 5 6 #include "alloc.h" 7 #include "debug.h" 8 #include "log.h" 9 #include "rcx.h" 10 #include "str.h" 11 12 /* TODO: e-versions of every function that can fail */ 13 14 static char * 15 r_str_vcat(char *buf, usize len, va_list args) { 16 ASSERT(buf || len == 0); 17 18 char *s; 19 usize need = 1; /* Null terminator */ 20 21 va_list args2; 22 va_copy(args2, args); 23 while ((s = va_arg(args2, char*))) { 24 usize slen = strlen(s); 25 if (slen > USIZE_MAX - need) { 26 va_end(args2); 27 errno = EOVERFLOW; 28 return 0; 29 } 30 need += slen; 31 } 32 va_end(args2); 33 34 if (buf && len < need) { 35 errno = ERANGE; 36 return 0; 37 } else if (!buf) { 38 buf = r_alloc(need); 39 if (!buf) 40 return 0; 41 } 42 43 char *b = buf; 44 while ((s = va_arg(args, char*))) { 45 while (*s) 46 *b++ = *s++; 47 } 48 *b = '\0'; 49 50 return buf; 51 } 52 53 char * 54 r_str_dup(char *s) { 55 char *dup = r_alloc(strlen(s) + 1); 56 if (!dup) return 0; 57 strcpy(dup, s); 58 return dup; 59 } 60 61 char * 62 r_str_edup(char *s) { 63 char *dup = r_str_dup(s); 64 if (!dup) r_fatalf("allocation failure"); 65 return dup; 66 } 67 68 char * 69 r_str_cat(char *buf, usize len, ...) { 70 va_list args; 71 va_start(args, len); 72 char *ret = r_str_vcat(buf, len, args); 73 va_end(args); 74 return ret; 75 } 76 77 char * 78 r_str_ecat(char *buf, usize len, ...) { 79 va_list args; 80 va_start(args, len); 81 char *ret = r_str_vcat(buf, len, args); 82 va_end(args); 83 if (!ret) 84 r_fatalf("r_str_ecat: %s", strerror(errno)); 85 return ret; 86 } 87 88 bool 89 r_str_starts_with(char *s, char *sub) { 90 return !strncmp(s, sub, strlen(sub)); 91 } 92 93 bool 94 r_str_ends_with(char *s, char *sub) { 95 usize slen = strlen(s); 96 usize sublen = strlen(sub); 97 return slen >= sublen && !strcmp(s + slen - sublen, sub); 98 } 99 100 usize 101 r_str_count(char *s, char *sub) { 102 usize n = 0; 103 usize sublen = strlen(sub); 104 while ((s = strstr(s, sub))) { 105 n++; 106 s += sublen; 107 } 108 return n; 109 } 110 111 usize 112 r_str_split(char ***fields, char *s, char *sep, usize n) { 113 ASSERT(strcmp(sep, ""), "separator must be nonempty"); 114 115 if (n == 0) { 116 n = r_str_count(s, sep) + 1; 117 if (!(*fields = r_allocn(n, sizeof **fields))) 118 return 0; 119 } 120 121 usize seplen = strlen(sep); 122 usize i = 0; 123 while (i < n - 1) { 124 char *t = strstr(s, sep); 125 if (!t) break; 126 (*fields)[i++] = s; 127 memset(t, 0, seplen); 128 s = t + seplen; 129 } 130 (*fields)[i++] = s; 131 132 return i; 133 } 134 135 int 136 r_vaprintf(char **s, const char *fmt, va_list args) { 137 va_list args2; 138 va_copy(args2, args); 139 int len = vsnprintf(0, 0, fmt, args2); 140 va_end(args2); 141 if (len < 0) 142 return len; 143 144 char *buf = r_alloc(len+1); 145 if (!buf) 146 return -1; 147 148 int ret = vsnprintf(buf, len+1, fmt, args); 149 if (ret < 0) 150 free(buf); 151 else 152 *s = buf; 153 154 return ret; 155 } 156 157 int 158 r_aprintf(char **s, const char *fmt, ...) { 159 va_list args; 160 va_start(args, fmt); 161 int ret = r_vaprintf(s, fmt, args); 162 va_end(args); 163 return ret; 164 }