27 #include <stdio.h> |
27 #include <stdio.h> |
28 #include <ctype.h> |
28 #include <ctype.h> |
29 #include <limits.h> |
29 #include <limits.h> |
30 |
30 |
31 char *flib_asprintf(const char *fmt, ...) { |
31 char *flib_asprintf(const char *fmt, ...) { |
32 va_list argp; |
32 va_list argp; |
33 va_start(argp, fmt); |
33 va_start(argp, fmt); |
34 char *result = flib_vasprintf(fmt, argp); |
34 char *result = flib_vasprintf(fmt, argp); |
35 va_end(argp); |
35 va_end(argp); |
36 return result; |
36 return result; |
37 } |
37 } |
38 |
38 |
39 char *flib_vasprintf(const char *fmt, va_list args) { |
39 char *flib_vasprintf(const char *fmt, va_list args) { |
40 char *result = NULL; |
40 char *result = NULL; |
41 if(!log_badargs_if(fmt==NULL)) { |
41 if(!log_badargs_if(fmt==NULL)) { |
42 int requiredSize = vsnprintf(NULL, 0, fmt, args)+1; // Figure out how much memory we need, |
42 int requiredSize = vsnprintf(NULL, 0, fmt, args)+1; // Figure out how much memory we need, |
43 if(!log_e_if(requiredSize<0, "Error formatting string with template \"%s\"", fmt)) { |
43 if(!log_e_if(requiredSize<0, "Error formatting string with template \"%s\"", fmt)) { |
44 char *tmpbuf = flib_malloc(requiredSize); // allocate it |
44 char *tmpbuf = flib_malloc(requiredSize); // allocate it |
45 if(tmpbuf && vsnprintf(tmpbuf, requiredSize, fmt, args)>=0) { // and then do the actual formatting. |
45 if(tmpbuf && vsnprintf(tmpbuf, requiredSize, fmt, args)>=0) { // and then do the actual formatting. |
46 result = tmpbuf; |
46 result = tmpbuf; |
47 tmpbuf = NULL; |
47 tmpbuf = NULL; |
48 } |
48 } |
49 free(tmpbuf); |
49 free(tmpbuf); |
50 } |
50 } |
51 } |
51 } |
52 return result; |
52 return result; |
53 } |
53 } |
54 |
54 |
55 char *flib_join(char **parts, int partCount, const char *delimiter) { |
55 char *flib_join(char **parts, int partCount, const char *delimiter) { |
56 char *result = NULL; |
56 char *result = NULL; |
57 if(!log_badargs_if2(parts==NULL, delimiter==NULL)) { |
57 if(!log_badargs_if2(parts==NULL, delimiter==NULL)) { |
58 size_t totalSize = 1; |
58 size_t totalSize = 1; |
59 size_t delimLen = strlen(delimiter); |
59 size_t delimLen = strlen(delimiter); |
60 for(int i=0; i<partCount; i++) { |
60 for(int i=0; i<partCount; i++) { |
61 totalSize += strlen(parts[i]) + delimLen; |
61 totalSize += strlen(parts[i]) + delimLen; |
62 } |
62 } |
63 result = flib_malloc(totalSize); |
63 result = flib_malloc(totalSize); |
64 |
64 |
65 if(result) { |
65 if(result) { |
66 size_t outpos = 0; |
66 size_t outpos = 0; |
67 for(int i=0; i<partCount; i++) { |
67 for(int i=0; i<partCount; i++) { |
68 if(i>0) { |
68 if(i>0) { |
69 strcpy(result+outpos, delimiter); |
69 strcpy(result+outpos, delimiter); |
70 outpos += delimLen; |
70 outpos += delimLen; |
71 } |
71 } |
72 strcpy(result+outpos, parts[i]); |
72 strcpy(result+outpos, parts[i]); |
73 outpos += strlen(parts[i]); |
73 outpos += strlen(parts[i]); |
74 } |
74 } |
75 } |
75 } |
76 } |
76 } |
77 return result; |
77 return result; |
78 } |
78 } |
79 |
79 |
80 char *flib_strdupnull(const char *str) { |
80 char *flib_strdupnull(const char *str) { |
81 return str==NULL ? NULL : flib_asprintf("%s", str); |
81 return str==NULL ? NULL : flib_asprintf("%s", str); |
82 } |
82 } |
83 |
83 |
84 void *flib_bufdupnull(const void *buf, size_t size) { |
84 void *flib_bufdupnull(const void *buf, size_t size) { |
85 void *result = NULL; |
85 void *result = NULL; |
86 if(!log_badargs_if(buf==NULL && size>0)) { |
86 if(!log_badargs_if(buf==NULL && size>0)) { |
87 result = flib_malloc(size); |
87 result = flib_malloc(size); |
88 if(result) { |
88 if(result) { |
89 memcpy(result, buf, size); |
89 memcpy(result, buf, size); |
90 } |
90 } |
91 } |
91 } |
92 return result; |
92 return result; |
93 } |
93 } |
94 |
94 |
95 void *flib_malloc(size_t size) { |
95 void *flib_malloc(size_t size) { |
96 void *result = malloc(size); |
96 void *result = malloc(size); |
97 if(!result && size>0) { |
97 if(!result && size>0) { |
98 flib_log_e("Out of memory trying to malloc %zu bytes.", size); |
98 flib_log_e("Out of memory trying to malloc %zu bytes.", size); |
99 } |
99 } |
100 return result; |
100 return result; |
101 } |
101 } |
102 |
102 |
103 void *flib_calloc(size_t count, size_t elementsize) { |
103 void *flib_calloc(size_t count, size_t elementsize) { |
104 void *result = calloc(count, elementsize); |
104 void *result = calloc(count, elementsize); |
105 if(!result && count>0 && elementsize>0) { |
105 if(!result && count>0 && elementsize>0) { |
106 flib_log_e("Out of memory trying to calloc %zu objects of %zu bytes each.", count, elementsize); |
106 flib_log_e("Out of memory trying to calloc %zu objects of %zu bytes each.", count, elementsize); |
107 } |
107 } |
108 return result; |
108 return result; |
109 } |
109 } |
110 |
110 |
111 void *flib_realloc(void *ptr, size_t size) { |
111 void *flib_realloc(void *ptr, size_t size) { |
112 void *result = realloc(ptr, size); |
112 void *result = realloc(ptr, size); |
113 if(!result && size>0) { |
113 if(!result && size>0) { |
114 flib_log_e("Out of memory trying to realloc %zu bytes.", size); |
114 flib_log_e("Out of memory trying to realloc %zu bytes.", size); |
115 } |
115 } |
116 return result; |
116 return result; |
117 } |
117 } |
118 |
118 |
119 static bool isAsciiAlnum(char c) { |
119 static bool isAsciiAlnum(char c) { |
120 return (c>='0' && c<='9') || (c>='a' && c <='z') || (c>='A' && c <='Z'); |
120 return (c>='0' && c<='9') || (c>='a' && c <='z') || (c>='A' && c <='Z'); |
121 } |
121 } |
122 |
122 |
123 char *flib_urlencode(const char *inbuf) { |
123 char *flib_urlencode(const char *inbuf) { |
124 return flib_urlencode_pred(inbuf, isAsciiAlnum); |
124 return flib_urlencode_pred(inbuf, isAsciiAlnum); |
125 } |
125 } |
126 |
126 |
127 static size_t countCharsToEscape(const char *inbuf, bool (*needsEscaping)(char c)) { |
127 static size_t countCharsToEscape(const char *inbuf, bool (*needsEscaping)(char c)) { |
128 size_t result = 0; |
128 size_t result = 0; |
129 for(const char *c=inbuf; *c; c++) { |
129 for(const char *c=inbuf; *c; c++) { |
130 if(needsEscaping(*c)) { |
130 if(needsEscaping(*c)) { |
131 result++; |
131 result++; |
132 } |
132 } |
133 } |
133 } |
134 return result; |
134 return result; |
135 } |
135 } |
136 |
136 |
137 char *flib_urlencode_pred(const char *inbuf, bool (*needsEscaping)(char c)) { |
137 char *flib_urlencode_pred(const char *inbuf, bool (*needsEscaping)(char c)) { |
138 char *result = NULL; |
138 char *result = NULL; |
139 if(inbuf && !log_badargs_if(needsEscaping == NULL)) { |
139 if(inbuf && !log_badargs_if(needsEscaping == NULL)) { |
140 size_t insize = strlen(inbuf); |
140 size_t insize = strlen(inbuf); |
141 if(!log_e_if(insize > SIZE_MAX/4, "String too long: %zu bytes.", insize)) { |
141 if(!log_e_if(insize > SIZE_MAX/4, "String too long: %zu bytes.", insize)) { |
142 size_t escapeCount = countCharsToEscape(inbuf, needsEscaping); |
142 size_t escapeCount = countCharsToEscape(inbuf, needsEscaping); |
143 result = flib_malloc(insize + escapeCount*2 + 1); |
143 result = flib_malloc(insize + escapeCount*2 + 1); |
144 } |
144 } |
145 if(result) { |
145 if(result) { |
146 char *out = result; |
146 char *out = result; |
147 for(const char *in = inbuf; *in; in++) { |
147 for(const char *in = inbuf; *in; in++) { |
148 if(!needsEscaping(*in)) { |
148 if(!needsEscaping(*in)) { |
149 *out = *in; |
149 *out = *in; |
150 out++; |
150 out++; |
151 } else { |
151 } else { |
152 snprintf(out, 4, "%%%02x", (unsigned)(*(uint8_t*)in)); |
152 snprintf(out, 4, "%%%02x", (unsigned)(*(uint8_t*)in)); |
153 out += 3; |
153 out += 3; |
154 } |
154 } |
155 } |
155 } |
156 *out = 0; |
156 *out = 0; |
157 } |
157 } |
158 } |
158 } |
159 return result; |
159 return result; |
160 } |
160 } |
161 |
161 |
162 char *flib_urldecode(const char *inbuf) { |
162 char *flib_urldecode(const char *inbuf) { |
163 if(!inbuf) { |
163 if(!inbuf) { |
164 return NULL; |
164 return NULL; |
165 } |
165 } |
166 char *outbuf = flib_malloc(strlen(inbuf)+1); |
166 char *outbuf = flib_malloc(strlen(inbuf)+1); |
167 if(!outbuf) { |
167 if(!outbuf) { |
168 return NULL; |
168 return NULL; |
169 } |
169 } |
170 |
170 |
171 size_t inpos = 0, outpos = 0; |
171 size_t inpos = 0, outpos = 0; |
172 while(inbuf[inpos]) { |
172 while(inbuf[inpos]) { |
173 if(inbuf[inpos] == '%' && isxdigit(inbuf[inpos+1]) && isxdigit(inbuf[inpos+2])) { |
173 if(inbuf[inpos] == '%' && isxdigit(inbuf[inpos+1]) && isxdigit(inbuf[inpos+2])) { |
174 char temp[3] = {inbuf[inpos+1],inbuf[inpos+2],0}; |
174 char temp[3] = {inbuf[inpos+1],inbuf[inpos+2],0}; |
175 outbuf[outpos++] = strtol(temp, NULL, 16); |
175 outbuf[outpos++] = strtol(temp, NULL, 16); |
176 inpos += 3; |
176 inpos += 3; |
177 } else { |
177 } else { |
178 outbuf[outpos++] = inbuf[inpos++]; |
178 outbuf[outpos++] = inbuf[inpos++]; |
179 } |
179 } |
180 } |
180 } |
181 outbuf[outpos] = 0; |
181 outbuf[outpos] = 0; |
182 char *shrunk = realloc(outbuf, outpos+1); |
182 char *shrunk = realloc(outbuf, outpos+1); |
183 return shrunk ? shrunk : outbuf; |
183 return shrunk ? shrunk : outbuf; |
184 } |
184 } |
185 |
185 |
186 bool flib_contains_dir_separator(const char *str) { |
186 bool flib_contains_dir_separator(const char *str) { |
187 if(!log_badargs_if(!str)) { |
187 if(!log_badargs_if(!str)) { |
188 for(;*str;str++) { |
188 for(;*str;str++) { |
189 if(*str=='\\' || *str=='/') { |
189 if(*str=='\\' || *str=='/') { |
190 return true; |
190 return true; |
191 } |
191 } |
192 } |
192 } |
193 } |
193 } |
194 return false; |
194 return false; |
195 } |
195 } |
196 |
196 |
197 bool flib_strempty(const char *str) { |
197 bool flib_strempty(const char *str) { |
198 return !str || !*str; |
198 return !str || !*str; |
199 } |
199 } |
200 |
200 |
201 int flib_gets(char *str, size_t strlen) { |
201 int flib_gets(char *str, size_t strlen) { |
202 if(fgets(str, strlen, stdin)) { |
202 if(fgets(str, strlen, stdin)) { |
203 for(char *s=str; *s; s++) { |
203 for(char *s=str; *s; s++) { |
204 if(*s=='\r' || *s=='\n') { |
204 if(*s=='\r' || *s=='\n') { |
205 *s = 0; |
205 *s = 0; |
206 break; |
206 break; |
207 } |
207 } |
208 } |
208 } |
209 return 0; |
209 return 0; |
210 } |
210 } |
211 return -1; |
211 return -1; |
212 } |
212 } |