Mercurial > hg > th-libs
comparison th_string.c @ 228:ca9cd98dbcff
Initial work on printf() style function family implementation.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Tue, 16 Feb 2016 13:59:51 +0200 |
parents | 128c8cb80205 |
children | 38a0719359ef |
comparison
equal
deleted
inserted
replaced
227:5f9de1d542ee | 228:ca9cd98dbcff |
---|---|
106 | 106 |
107 return th_strdup_trim_do(src, len, flags); | 107 return th_strdup_trim_do(src, len, flags); |
108 } | 108 } |
109 | 109 |
110 | 110 |
111 /* Simple implementations of printf() type functions | |
112 */ | |
113 static int th_vput_itoa(void *ctx, int (*vputch)(void *ctx, const char ch), int val, int radix, char padMode, int width, BOOL unsig, BOOL upcase, BOOL sign) | |
114 { | |
115 char buf[64]; | |
116 size_t pos = 0; | |
117 BOOL neg = FALSE; | |
118 int ret = 0; | |
119 | |
120 if (radix > 16) | |
121 return 0; | |
122 | |
123 if (val < 0) | |
124 { | |
125 neg = TRUE; | |
126 val = -val; | |
127 } | |
128 | |
129 do | |
130 { | |
131 int digit = val % radix; | |
132 if (digit < 10) | |
133 buf[pos] = '0' + digit; | |
134 else | |
135 buf[pos] = (upcase ? 'A' : 'a') + digit - 10; | |
136 val /= radix; | |
137 pos++; | |
138 } | |
139 while (val > 0 && pos < sizeof(buf) - 1); | |
140 buf[pos] = 0; | |
141 | |
142 if (!unsig) | |
143 { | |
144 char ch = sign ? (neg ? '-' : '+') : (neg ? '-' : 0); | |
145 if (ch && (ret = vputch(ctx, ch)) == EOF) | |
146 goto out; | |
147 } | |
148 | |
149 int nwidth = width - pos; | |
150 | |
151 if (nwidth > 0 && padMode != '-') | |
152 { | |
153 while (nwidth--) | |
154 if ((ret = vputch(ctx, padMode)) == EOF) | |
155 goto out; | |
156 } | |
157 | |
158 while (pos--) | |
159 { | |
160 if ((ret = vputch(ctx, buf[pos])) == EOF) | |
161 goto out; | |
162 } | |
163 | |
164 if (nwidth > 0 && padMode == '-') | |
165 { | |
166 while (nwidth--) | |
167 if ((ret = vputch(ctx, ' ')) == EOF) | |
168 goto out; | |
169 } | |
170 | |
171 out: | |
172 return ret; | |
173 } | |
174 | |
175 | |
176 static int th_vput_str(void *ctx, int (*vputch)(void *ctx, const char ch), const char *str, char padMode, int width) | |
177 { | |
178 int nwidth = width - strlen(str); | |
179 int ret = 0; | |
180 | |
181 if (nwidth > 0 && padMode != '-') | |
182 { | |
183 while (nwidth--) | |
184 if ((ret = vputch(ctx, padMode)) == EOF) | |
185 goto out; | |
186 } | |
187 | |
188 while (*str) | |
189 { | |
190 if ((ret = vputch(ctx, *str++)) == EOF) | |
191 goto out; | |
192 } | |
193 | |
194 if (nwidth > 0 && padMode == '-') | |
195 { | |
196 while (nwidth--) | |
197 if ((ret = vputch(ctx, ' ')) == EOF) | |
198 goto out; | |
199 } | |
200 | |
201 out: | |
202 return ret; | |
203 } | |
204 | |
205 | |
206 int th_vprintf_do(void *ctx, int (*vputch)(void *ctx, const char ch), const char *fmt, va_list ap) | |
207 { | |
208 int ret; | |
209 | |
210 while (*fmt) | |
211 { | |
212 if (*fmt != '%') | |
213 { | |
214 if ((ret = vputch(ctx, *fmt)) == EOF) | |
215 return ret; | |
216 } | |
217 else | |
218 { | |
219 char padMode = ' ', padChar = 0; | |
220 BOOL sign = FALSE; | |
221 int width = 0; | |
222 | |
223 fmt++; | |
224 | |
225 if (*fmt == '+') | |
226 { | |
227 sign = TRUE; | |
228 fmt++; | |
229 } | |
230 | |
231 if (*fmt == '0' || *fmt == '-' || *fmt == '\'') | |
232 { | |
233 padMode = *fmt++; | |
234 if (padMode == '\'') | |
235 { | |
236 padChar = *fmt++; | |
237 if (*fmt != '\'') | |
238 goto out; | |
239 fmt++; | |
240 } | |
241 | |
242 if (*fmt == 0) | |
243 goto out; | |
244 } | |
245 | |
246 while (th_isdigit(*fmt)) | |
247 width = width * 10 + (*fmt++ - '0'); | |
248 | |
249 switch (*fmt) | |
250 { | |
251 case '%': | |
252 vputch(ctx, *fmt); | |
253 break; | |
254 | |
255 case 0: | |
256 goto out; | |
257 | |
258 case 'u': | |
259 case 'd': | |
260 if (padMode != '0' && padMode != '-' && padMode != ' ') | |
261 goto out; | |
262 | |
263 if ((ret = th_vput_itoa(ctx, vputch, va_arg(ap, unsigned int), 10, padMode, width, *fmt == 'u', FALSE, sign)) == EOF) | |
264 goto out; | |
265 break; | |
266 | |
267 case 'x': | |
268 case 'X': | |
269 if (padMode != '0' && padMode != '-' && padMode != ' ') | |
270 goto out; | |
271 | |
272 if ((ret = th_vput_itoa(ctx, vputch, va_arg(ap, unsigned int), 16, padMode, width, TRUE, *fmt == 'X', FALSE)) == EOF) | |
273 goto out; | |
274 break; | |
275 | |
276 case 'f': | |
277 goto out; | |
278 | |
279 case 's': | |
280 if (padMode != '-' && padMode != ' ') | |
281 goto out; | |
282 | |
283 if ((ret = th_vput_str(ctx, vputch, va_arg(ap, char *), padMode, width)) == EOF) | |
284 goto out; | |
285 break; | |
286 | |
287 default: | |
288 vputch(ctx, *fmt); | |
289 break; | |
290 } | |
291 } | |
292 fmt++; | |
293 } | |
294 out: | |
295 return ret; | |
296 } | |
297 | |
298 | |
299 typedef struct | |
300 { | |
301 char *buf; | |
302 size_t size, pos; | |
303 } th_pbuf_ctx; | |
304 | |
305 | |
306 static int th_pbuf_vputch(void *pctx, const char ch) | |
307 { | |
308 th_pbuf_ctx *ctx = (th_pbuf_ctx *) pctx; | |
309 if (ctx->pos < ctx->size) | |
310 ctx->buf[ctx->pos] = ch; | |
311 ctx->pos++; | |
312 return ch; | |
313 } | |
314 | |
315 | |
316 int th_vsnprintf(char *buf, size_t size, const char *fmt, va_list ap) | |
317 { | |
318 #ifdef TH_USE_INTERNAL_SPRINTF | |
319 th_pbuf_ctx ctx; | |
320 ctx.buf = buf; | |
321 ctx.size = size; | |
322 ctx.pos = 0; | |
323 | |
324 return th_vprintf_do((void *) &ctx, th_pbuf_vputch, fmt, ap); | |
325 #else | |
326 return vsnpintf(buf, size, fmt, ap); | |
327 #endif | |
328 } | |
329 | |
330 | |
331 int th_snprintf(char *buf, size_t size, const char *fmt, ...) | |
332 { | |
333 int n; | |
334 va_list ap; | |
335 va_start(ap, fmt); | |
336 #ifdef TH_USE_INTERNAL_SPRINTF | |
337 n = th_vsnprintf(buf, size, fmt, ap); | |
338 #else | |
339 n = vsnprintf(buf, size, fmt, ap); | |
340 #endif | |
341 va_end(ap); | |
342 return n; | |
343 } | |
344 | |
345 | |
346 static int th_stdio_vputch(void *ctx, const char ch) | |
347 { | |
348 return fputc(ch, (FILE *) ctx); | |
349 } | |
350 | |
351 | |
352 int th_vfprintf(FILE *fh, const char *fmt, va_list ap) | |
353 { | |
354 #ifdef TH_USE_INTERNAL_SPRINTF | |
355 return th_vprintf_do((void *) fh, th_stdio_vputch, fmt, ap); | |
356 #else | |
357 return vfprintf(fh, fmt, ap); | |
358 #endif | |
359 } | |
360 | |
361 | |
362 int th_fprintf(FILE *fh, const char *fmt, ...) | |
363 { | |
364 int ret; | |
365 va_list ap; | |
366 va_start(ap, fmt); | |
367 #ifdef TH_USE_INTERNAL_SPRINTF | |
368 ret = th_vprintf_do((void *) fh, th_stdio_vputch, fmt, ap); | |
369 #else | |
370 ret = fprintf(fh, fmt, ap); | |
371 #endif | |
372 va_end(ap); | |
373 return ret; | |
374 } | |
375 | |
376 | |
111 /* Simulate a sprintf() that allocates memory | 377 /* Simulate a sprintf() that allocates memory |
112 */ | 378 */ |
113 char *th_strdup_vprintf(const char *fmt, va_list args) | 379 char *th_strdup_vprintf(const char *fmt, va_list args) |
114 { | 380 { |
115 int size = 64; | 381 int size = 64; |
121 while (1) | 387 while (1) |
122 { | 388 { |
123 int n; | 389 int n; |
124 va_list ap; | 390 va_list ap; |
125 va_copy(ap, args); | 391 va_copy(ap, args); |
392 #ifdef TH_USE_INTERNAL_SPRINTF | |
393 n = th_vsnprintf(buf, size, fmt, ap); | |
394 #else | |
126 n = vsnprintf(buf, size, fmt, ap); | 395 n = vsnprintf(buf, size, fmt, ap); |
396 #endif | |
127 va_end(ap); | 397 va_end(ap); |
128 | 398 |
129 if (n > -1 && n < size) | 399 if (n > -1 && n < size) |
130 return buf; | 400 return buf; |
131 if (n > -1) | 401 if (n > -1) |
230 return NULL; | 500 return NULL; |
231 | 501 |
232 const size_t | 502 const size_t |
233 slen = strlen(str), | 503 slen = strlen(str), |
234 nlen = strlen(needle); | 504 nlen = strlen(needle); |
235 | 505 |
236 if (slen < nlen) | 506 if (slen < nlen) |
237 return NULL; | 507 return NULL; |
238 | 508 |
239 if (th_strcasecmp(str - nlen - 1, needle) == 0) | 509 if (th_strcasecmp(str - nlen - 1, needle) == 0) |
240 return str - nlen - 1; | 510 return str - nlen - 1; |