Mercurial > dovecot > core-2.2
annotate src/lib/strfuncs.c @ 5:1b34ec11fff8 HEAD
Message data is parsed in blocks (no longer entirely mmap()ed). Several
IOBuffer changes. All mixed signed/unsigned comparisions were fixed so code
can now be compiled with gcc's -W flag. mbox support is broken currently,
and there's most likely several other problems too.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Thu, 22 Aug 2002 01:10:20 +0300 |
parents | 3b1985cbc908 |
children | 2d8711a043a0 |
rev | line source |
---|---|
0 | 1 /* |
2 strfuncs.c : String manipulation functions (note: LGPL, because the ) | |
3 | |
4 Copyright (C) 2001-2002 Timo Sirainen | |
5 | |
6 printf_string_upper_bound() code is taken from GLIB: | |
7 Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald | |
8 Modified by the GLib Team and others 1997-1999. | |
9 | |
10 | |
11 This library is free software; you can redistribute it and/or | |
12 modify it under the terms of the GNU Library General Public | |
13 License as published by the Free Software Foundation; either | |
14 version 2 of the License, or (at your option) any later version. | |
15 | |
16 This library is distributed in the hope that it will be useful, | |
17 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 Library General Public License for more details. | |
20 | |
21 You should have received a copy of the GNU Library General Public | |
22 License along with this library; if not, write to the | |
23 Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
24 Boston, MA 02111-1307, USA. | |
25 */ | |
26 | |
27 #include "lib.h" | |
28 #include "strfuncs.h" | |
29 | |
30 #include <stdio.h> | |
31 #include <limits.h> | |
32 #include <ctype.h> | |
33 | |
34 #define STRCONCAT_BUFSIZE 512 | |
35 | |
36 typedef void *(*ALLOC_FUNC)(Pool, unsigned int); | |
37 | |
38 static void *tp_malloc(Pool pool __attr_unused__, unsigned int size) | |
39 { | |
40 return t_malloc(size); | |
41 } | |
42 | |
43 typedef union _GDoubleIEEE754 GDoubleIEEE754; | |
44 #define G_IEEE754_DOUBLE_BIAS (1023) | |
45 /* multiply with base2 exponent to get base10 exponent (nomal numbers) */ | |
46 #define G_LOG_2_BASE_10 (0.30102999566398119521) | |
47 #if G_BYTE_ORDER == G_LITTLE_ENDIAN | |
48 union _GDoubleIEEE754 | |
49 { | |
50 double v_double; | |
51 struct { | |
52 unsigned int mantissa_low : 32; | |
53 unsigned int mantissa_high : 20; | |
54 unsigned int biased_exponent : 11; | |
55 unsigned int sign : 1; | |
56 } mpn; | |
57 }; | |
58 #elif G_BYTE_ORDER == G_BIG_ENDIAN | |
59 union _GDoubleIEEE754 | |
60 { | |
61 double v_double; | |
62 struct { | |
63 unsigned int sign : 1; | |
64 unsigned int biased_exponent : 11; | |
65 unsigned int mantissa_high : 20; | |
66 unsigned int mantissa_low : 32; | |
67 } mpn; | |
68 }; | |
69 #else /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */ | |
70 #error unknown ENDIAN type | |
71 #endif /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */ | |
72 | |
73 typedef struct | |
74 { | |
75 unsigned int min_width; | |
76 unsigned int precision; | |
77 int alternate_format, zero_padding, adjust_left, locale_grouping; | |
78 int add_space, add_sign, possible_sign, seen_precision; | |
79 int mod_half, mod_long, mod_extra_long; | |
80 } PrintfArgSpec; | |
81 | |
82 #if (SIZEOF_LONG > 4) || (SIZEOF_VOID_P > 4) | |
83 # define HONOUR_LONGS 1 | |
84 #else | |
85 # define HONOUR_LONGS 0 | |
86 #endif | |
87 | |
88 unsigned int printf_string_upper_bound(const char *format, va_list args) | |
89 { | |
90 int len = 1; | |
91 | |
92 if (!format) | |
93 return len; | |
94 | |
95 while (*format) | |
96 { | |
97 register char c = *format++; | |
98 | |
99 if (c != '%') | |
100 len += 1; | |
101 else /* (c == '%') */ | |
102 { | |
103 PrintfArgSpec spec; | |
104 int seen_l = FALSE, conv_done = FALSE; | |
105 unsigned int conv_len = 0; | |
106 const char *spec_start = format; | |
107 | |
108 memset(&spec, 0, sizeof(spec)); | |
109 do | |
110 { | |
111 c = *format++; | |
112 switch (c) | |
113 { | |
114 GDoubleIEEE754 u_double; | |
115 unsigned int v_uint; | |
116 int v_int; | |
117 const char *v_string; | |
118 | |
119 /* beware of positional parameters | |
120 */ | |
121 case '$': | |
122 i_warning (GNUC_PRETTY_FUNCTION | |
123 "(): unable to handle positional parameters (%%n$)"); | |
124 len += 1024; /* try adding some safety padding */ | |
125 break; | |
126 | |
127 /* parse flags | |
128 */ | |
129 case '#': | |
130 spec.alternate_format = TRUE; | |
131 break; | |
132 case '0': | |
133 spec.zero_padding = TRUE; | |
134 break; | |
135 case '-': | |
136 spec.adjust_left = TRUE; | |
137 break; | |
138 case ' ': | |
139 spec.add_space = TRUE; | |
140 break; | |
141 case '+': | |
142 spec.add_sign = TRUE; | |
143 break; | |
144 case '\'': | |
145 spec.locale_grouping = TRUE; | |
146 break; | |
147 | |
148 /* parse output size specifications | |
149 */ | |
150 case '.': | |
151 spec.seen_precision = TRUE; | |
152 break; | |
153 case '1': | |
154 case '2': | |
155 case '3': | |
156 case '4': | |
157 case '5': | |
158 case '6': | |
159 case '7': | |
160 case '8': | |
161 case '9': | |
162 v_uint = c - '0'; | |
163 c = *format; | |
164 while (c >= '0' && c <= '9') | |
165 { | |
166 format++; | |
167 v_uint = v_uint * 10 + c - '0'; | |
168 c = *format; | |
169 } | |
170 if (spec.seen_precision) | |
171 spec.precision = I_MAX (spec.precision, v_uint); | |
172 else | |
173 spec.min_width = I_MAX (spec.min_width, v_uint); | |
174 break; | |
175 case '*': | |
176 v_int = va_arg (args, int); | |
177 if (spec.seen_precision) | |
178 { | |
179 /* forget about negative precision */ | |
180 if (v_int >= 0) | |
181 spec.precision = I_MAX ((int)spec.precision, v_int); | |
182 } | |
183 else | |
184 { | |
185 if (v_int < 0) | |
186 { | |
187 v_int = - v_int; | |
188 spec.adjust_left = TRUE; | |
189 } | |
190 spec.min_width = I_MAX ((int)spec.min_width, v_int); | |
191 } | |
192 break; | |
193 | |
194 /* parse type modifiers | |
195 */ | |
196 case 'h': | |
197 spec.mod_half = TRUE; | |
198 break; | |
199 case 'l': | |
200 if (!seen_l) | |
201 { | |
202 spec.mod_long = TRUE; | |
203 seen_l = TRUE; | |
204 break; | |
205 } | |
206 /* else, fall through */ | |
207 case 'L': | |
208 case 'q': | |
209 spec.mod_long = TRUE; | |
210 spec.mod_extra_long = TRUE; | |
211 break; | |
212 case 'z': | |
213 case 'Z': | |
214 #if GLIB_SIZEOF_SIZE_T > 4 | |
215 spec.mod_long = TRUE; | |
216 spec.mod_extra_long = TRUE; | |
217 #endif /* GLIB_SIZEOF_SIZE_T > 4 */ | |
218 break; | |
219 case 't': | |
220 #if GLIB_SIZEOF_PTRDIFF_T > 4 | |
221 spec.mod_long = TRUE; | |
222 spec.mod_extra_long = TRUE; | |
223 #endif /* GLIB_SIZEOF_PTRDIFF_T > 4 */ | |
224 break; | |
225 case 'j': | |
226 #if GLIB_SIZEOF_INTMAX_T > 4 | |
227 spec.mod_long = TRUE; | |
228 spec.mod_extra_long = TRUE; | |
229 #endif /* GLIB_SIZEOF_INTMAX_T > 4 */ | |
230 break; | |
231 | |
232 /* parse output conversions | |
233 */ | |
234 case '%': | |
235 conv_len += 1; | |
236 break; | |
237 case 'O': | |
238 case 'D': | |
239 case 'I': | |
240 case 'U': | |
241 /* some C libraries feature long variants for these as well? */ | |
242 spec.mod_long = TRUE; | |
243 /* fall through */ | |
244 case 'o': | |
245 conv_len += 2; | |
246 /* fall through */ | |
247 case 'd': | |
248 case 'i': | |
249 conv_len += 1; /* sign */ | |
250 /* fall through */ | |
251 case 'u': | |
252 conv_len += 4; | |
253 /* fall through */ | |
254 case 'x': | |
255 case 'X': | |
256 spec.possible_sign = TRUE; | |
257 conv_len += 10; | |
258 if (spec.mod_long && HONOUR_LONGS) | |
259 conv_len *= 2; | |
260 if (spec.mod_extra_long) | |
261 conv_len *= 2; | |
262 if (spec.mod_extra_long) | |
263 { | |
264 #ifdef G_HAVE_GINT64 | |
265 (void) va_arg (args, gint64); | |
266 #else | |
267 (void) va_arg (args, long); | |
268 #endif | |
269 } | |
270 else if (spec.mod_long) | |
271 (void) va_arg (args, long); | |
272 else | |
273 (void) va_arg (args, int); | |
274 break; | |
275 case 'A': | |
276 case 'a': | |
277 /* 0x */ | |
278 conv_len += 2; | |
279 /* fall through */ | |
280 case 'g': | |
281 case 'G': | |
282 case 'e': | |
283 case 'E': | |
284 case 'f': | |
285 spec.possible_sign = TRUE; | |
286 /* n . dddddddddddddddddddddddd E +- eeee */ | |
287 conv_len += 1 + 1 + I_MAX (24, spec.precision) + 1 + 1 + 4; | |
288 if (spec.mod_extra_long) | |
289 i_warning (GNUC_PRETTY_FUNCTION | |
290 "(): unable to handle long double, collecting double only"); | |
291 #ifdef HAVE_LONG_DOUBLE | |
292 #error need to implement special handling for long double | |
293 #endif | |
294 u_double.v_double = va_arg (args, double); | |
295 /* %f can expand up to all significant digits before '.' (308) */ | |
296 if (c == 'f' && | |
297 u_double.mpn.biased_exponent > 0 && u_double.mpn.biased_exponent < 2047) | |
298 { | |
299 int exp = u_double.mpn.biased_exponent; | |
300 | |
301 exp -= G_IEEE754_DOUBLE_BIAS; | |
302 exp = exp * G_LOG_2_BASE_10 + 1; | |
303 conv_len += exp; | |
304 } | |
305 /* some printf() implementations require extra padding for rounding */ | |
306 conv_len += 2; | |
307 /* we can't really handle locale specific grouping here */ | |
308 if (spec.locale_grouping) | |
309 conv_len *= 2; | |
310 break; | |
311 case 'C': | |
312 spec.mod_long = TRUE; | |
313 /* fall through */ | |
314 case 'c': | |
315 conv_len += spec.mod_long ? MB_LEN_MAX : 1; | |
316 (void) va_arg (args, int); | |
317 break; | |
318 case 'S': | |
319 spec.mod_long = TRUE; | |
320 /* fall through */ | |
321 case 's': | |
322 v_string = va_arg (args, char*); | |
323 if (!v_string) | |
324 conv_len += 8; /* hold "(null)" */ | |
325 else if (spec.seen_precision) | |
326 conv_len += spec.precision; | |
327 else | |
328 conv_len += strlen (v_string); | |
329 conv_done = TRUE; | |
330 if (spec.mod_long) | |
331 { | |
332 i_warning (GNUC_PRETTY_FUNCTION | |
333 "(): unable to handle wide char strings"); | |
334 len += 1024; /* try adding some safety padding */ | |
335 } | |
336 break; | |
337 case 'P': /* do we actually need this? */ | |
338 /* fall through */ | |
339 case 'p': | |
340 spec.alternate_format = TRUE; | |
341 conv_len += 10; | |
342 if (HONOUR_LONGS) | |
343 conv_len *= 2; | |
344 /* fall through */ | |
345 case 'n': | |
346 conv_done = TRUE; | |
347 (void) va_arg (args, void*); | |
348 break; | |
349 case 'm': | |
350 /* there's not much we can do to be clever */ | |
351 v_string = strerror (errno); | |
352 v_uint = v_string ? strlen (v_string) : 0; | |
353 conv_len += I_MAX (256, v_uint); | |
354 break; | |
355 | |
356 /* handle invalid cases | |
357 */ | |
358 case '\000': | |
359 /* no conversion specification, bad bad */ | |
360 conv_len += format - spec_start; | |
361 break; | |
362 default: | |
363 i_warning (GNUC_PRETTY_FUNCTION | |
364 "(): unable to handle `%c' while parsing format", | |
365 c); | |
366 break; | |
367 } | |
368 conv_done |= conv_len > 0; | |
369 } | |
370 while (!conv_done); | |
371 /* handle width specifications */ | |
372 conv_len = I_MAX (conv_len, I_MAX (spec.precision, spec.min_width)); | |
373 /* handle flags */ | |
374 conv_len += spec.alternate_format ? 2 : 0; | |
375 conv_len += (spec.add_space || spec.add_sign || spec.possible_sign); | |
376 /* finally done */ | |
377 len += conv_len; | |
378 } /* else (c == '%') */ | |
379 } /* while (*format) */ | |
380 | |
381 return len; | |
382 } | |
383 | |
384 static const char *fix_format_real(const char *fmt, const char *p) | |
385 { | |
386 const char *errstr; | |
387 char *buf; | |
388 unsigned int pos, alloc, errlen; | |
389 | |
390 errstr = strerror(errno); | |
391 errlen = strlen(errstr); | |
392 | |
393 pos = (unsigned int) (p-fmt); | |
394 i_assert(pos < INT_MAX); | |
395 | |
396 alloc = pos + errlen + 128; | |
397 buf = t_buffer_get(alloc); | |
398 | |
399 memcpy(buf, fmt, pos); | |
400 | |
401 while (*p != '\0') { | |
402 if (*p == '%' && p[1] == 'm') { | |
403 if (pos+errlen+1 > alloc) { | |
404 alloc += errlen+1 + 128; | |
405 buf = t_buffer_get(alloc); | |
406 } | |
407 | |
408 memcpy(buf+pos, errstr, errlen); | |
409 pos += errlen; | |
410 p += 2; | |
411 } else { | |
412 /* p + \0 */ | |
413 if (pos+2 > alloc) { | |
414 alloc += 128; | |
415 buf = t_buffer_get(alloc); | |
416 } | |
417 | |
418 buf[pos++] = *p; | |
419 p++; | |
420 } | |
421 } | |
422 | |
423 buf[pos++] = '\0'; | |
424 t_buffer_alloc(pos); | |
425 return buf; | |
426 } | |
427 | |
428 /* replace %m with strerror() */ | |
429 static const char *fix_format(const char *fmt) | |
430 { | |
431 const char *p; | |
432 | |
433 for (p = fmt; *p != '\0'; p++) { | |
434 if (*p == '%' && p[1] == 'm') | |
435 return fix_format_real(fmt, p); | |
436 } | |
437 | |
438 return fmt; | |
439 } | |
440 | |
441 int i_snprintf(char *str, unsigned int max_chars, const char *format, ...) | |
442 { | |
443 #ifdef HAVE_VSNPRINTF | |
444 va_list args; | |
445 int ret; | |
446 | |
447 i_assert(str != NULL); | |
448 i_assert(max_chars < INT_MAX); | |
449 i_assert(format != NULL); | |
450 | |
451 va_start(args, format); | |
452 ret = vsnprintf(str, max_chars, fix_format(format), args); | |
453 va_end(args); | |
454 | |
455 if (ret < 0) { | |
456 str[max_chars-1] = '\0'; | |
457 ret = strlen(str); | |
458 } | |
459 | |
460 return ret; | |
461 #else | |
462 char *buf; | |
463 va_list args; | |
464 int len; | |
465 | |
466 i_assert(str != NULL); | |
467 i_assert(max_chars < INT_MAX); | |
468 i_assert(format != NULL); | |
469 | |
470 va_start(args, format); | |
471 format = fix_format(format); | |
472 buf = t_buffer_get(printf_string_upper_bound(format, args)); | |
473 va_end(args); | |
474 | |
475 len = vsprintf(buf, format, args); | |
476 if (len >= (int)max_chars) | |
477 len = max_chars-1; | |
478 | |
479 memcpy(str, buf, len); | |
480 str[len] = '\0'; | |
481 return len; | |
482 #endif | |
483 } | |
484 | |
485 #define STRDUP_CORE(alloc_func, str) STMT_START { \ | |
486 void *mem; \ | |
487 unsigned int len; \ | |
488 \ | |
489 for (len = 0; (str)[len] != '\0'; ) \ | |
490 len++; \ | |
491 len++; \ | |
492 mem = alloc_func; \ | |
493 memcpy(mem, str, sizeof(str[0])*len); \ | |
494 return mem; \ | |
495 } STMT_END | |
496 | |
497 char *p_strdup(Pool pool, const char *str) | |
498 { | |
499 if (str == NULL) | |
500 return NULL; | |
501 | |
502 STRDUP_CORE(p_malloc(pool, len), str); | |
503 } | |
504 | |
505 const char *t_strdup(const char *str) | |
506 { | |
507 if (str == NULL) | |
508 return NULL; | |
509 | |
510 STRDUP_CORE(t_malloc(len), str); | |
511 } | |
512 | |
513 int *p_intarrdup(Pool pool, const int *arr) | |
514 { | |
515 if (arr == NULL) | |
516 return NULL; | |
517 | |
518 STRDUP_CORE(p_malloc(pool, sizeof(int) * len), arr); | |
519 } | |
520 | |
521 const int *t_intarrdup(const int *arr) | |
522 { | |
523 if (arr == NULL) | |
524 return NULL; | |
525 | |
526 STRDUP_CORE(t_malloc(sizeof(int) * len), arr); | |
527 } | |
528 | |
529 #define STRDUP_EMPTY_CORE(alloc_func, str) STMT_START { \ | |
530 if ((str) == NULL || (str)[0] == '\0') \ | |
531 return NULL; \ | |
532 \ | |
533 STRDUP_CORE(alloc_func, str); \ | |
534 } STMT_END | |
535 | |
536 | |
537 char *p_strdup_empty(Pool pool, const char *str) | |
538 { | |
539 STRDUP_EMPTY_CORE(p_malloc(pool, len), str); | |
540 } | |
541 | |
542 const char *t_strdup_empty(const char *str) | |
543 { | |
544 STRDUP_EMPTY_CORE(t_malloc(len), str); | |
545 } | |
546 | |
5
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
547 char *p_strdup_until(Pool pool, const char *start, const char *end) |
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
548 { |
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
549 unsigned int size; |
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
550 char *mem; |
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
551 |
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
552 i_assert(start <= end); |
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
553 |
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
554 size = (unsigned int) (end-start); |
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
555 mem = p_malloc(pool, size+1); |
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
556 memcpy(mem, start, size); |
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
557 return mem; |
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
558 } |
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
559 |
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
560 const char *t_strdup_until(const char *start, const char *end) |
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
561 { |
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
562 unsigned int size; |
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
563 char *mem; |
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
564 |
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
565 i_assert(start <= end); |
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
566 |
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
567 size = (unsigned int) (end-start); |
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
568 mem = t_malloc(size+1); |
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
569 memcpy(mem, start, size); |
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
570 mem[size] = '\0'; |
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
571 return mem; |
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
572 } |
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
573 |
0 | 574 static inline char * |
575 strndup_core(const char *str, unsigned int max_chars, | |
576 ALLOC_FUNC alloc, Pool pool) | |
577 { | |
578 char *mem; | |
579 unsigned int len; | |
580 | |
581 i_assert(max_chars < INT_MAX); | |
582 | |
583 if (str == NULL) | |
584 return NULL; | |
585 | |
586 len = 0; | |
587 while (str[len] != '\0' && len < max_chars) | |
588 len++; | |
589 | |
590 mem = alloc(pool, len+1); | |
591 memcpy(mem, str, len); | |
592 mem[len] = '\0'; | |
593 return mem; | |
594 } | |
595 | |
596 char *p_strndup(Pool pool, const char *str, unsigned int max_chars) | |
597 { | |
598 return strndup_core(str, max_chars, pool->malloc, pool); | |
599 } | |
600 | |
601 const char *t_strndup(const char *str, unsigned int max_chars) | |
602 { | |
603 return strndup_core(str, max_chars, tp_malloc, NULL); | |
604 } | |
605 | |
606 char *p_strdup_printf(Pool pool, const char *format, ...) | |
607 { | |
608 va_list args; | |
609 char *ret; | |
610 | |
611 va_start(args, format); | |
612 ret = p_strdup_vprintf(pool, format, args); | |
613 va_end(args); | |
614 | |
615 return ret; | |
616 } | |
617 | |
618 const char *t_strdup_printf(const char *format, ...) | |
619 { | |
620 va_list args; | |
621 const char *ret; | |
622 | |
623 va_start(args, format); | |
624 ret = t_strdup_vprintf(format, args); | |
625 va_end(args); | |
626 | |
627 return ret; | |
628 } | |
629 | |
630 static inline char * | |
631 strdup_vprintf_core(const char *format, va_list args, | |
632 ALLOC_FUNC alloc_func, Pool pool) | |
633 { | |
634 va_list temp_args; | |
635 char *ret; | |
636 | |
637 if (format == NULL) | |
638 return NULL; | |
639 format = fix_format(format); | |
640 | |
641 VA_COPY(temp_args, args); | |
642 | |
643 ret = alloc_func(pool, printf_string_upper_bound(format, args)); | |
644 vsprintf(ret, format, args); | |
645 | |
646 va_end(temp_args); | |
647 | |
648 return ret; | |
649 } | |
650 | |
651 char *p_strdup_vprintf(Pool pool, const char *format, va_list args) | |
652 { | |
653 return strdup_vprintf_core(format, args, pool->malloc, pool); | |
654 } | |
655 | |
656 const char *t_strdup_vprintf(const char *format, va_list args) | |
657 { | |
658 return strdup_vprintf_core(format, args, tp_malloc, NULL); | |
659 } | |
660 | |
661 void p_strdup_replace(Pool pool, char **dest, const char *str) | |
662 { | |
663 p_free(pool, *dest); | |
664 *dest = p_strdup(pool, str); | |
665 } | |
666 | |
667 const char *temp_strconcat(const char *str1, va_list args, | |
668 unsigned int *ret_len) | |
669 { | |
670 const char *str; | |
671 char *temp; | |
672 unsigned int full_len, len, bufsize; | |
673 | |
674 if (str1 == NULL) | |
675 return NULL; | |
676 | |
677 /* put str1 to buffer */ | |
678 len = strlen(str1); | |
679 bufsize = len <= STRCONCAT_BUFSIZE ? STRCONCAT_BUFSIZE : | |
680 nearest_power(len+1); | |
681 temp = t_buffer_get(bufsize); | |
682 | |
683 memcpy(temp, str1, len); | |
684 full_len = len; | |
685 | |
686 /* put rest of the strings to buffer */ | |
687 while ((str = va_arg(args, char *)) != NULL) { | |
688 len = strlen(str); | |
689 if (len == 0) | |
690 continue; | |
691 | |
692 if (bufsize < full_len+len+1) { | |
693 bufsize = nearest_power(bufsize+len+1); | |
694 temp = t_buffer_reget(temp, bufsize); | |
695 } | |
696 | |
697 memcpy(temp+full_len, str, len); | |
698 full_len += len; | |
699 } | |
700 | |
701 temp[full_len] = '\0'; | |
702 *ret_len = full_len+1; | |
703 return temp; | |
704 } | |
705 | |
706 char *p_strconcat(Pool pool, const char *str1, ...) | |
707 { | |
708 va_list args; | |
709 const char *temp; | |
710 char *ret; | |
711 unsigned int len; | |
712 | |
713 va_start(args, str1); | |
714 | |
715 temp = temp_strconcat(str1, args, &len); | |
716 if (temp == NULL) | |
717 ret = NULL; | |
718 else { | |
719 ret = p_malloc(pool, len); | |
720 memcpy(ret, temp, len); | |
721 } | |
722 | |
723 va_end(args); | |
724 return ret; | |
725 } | |
726 | |
727 const char *t_strconcat(const char *str1, ...) | |
728 { | |
729 va_list args; | |
730 const char *ret; | |
731 unsigned int len; | |
732 | |
733 va_start(args, str1); | |
734 | |
735 ret = temp_strconcat(str1, args, &len); | |
736 if (ret != NULL) | |
737 t_buffer_alloc(len); | |
738 | |
739 va_end(args); | |
740 return ret; | |
741 } | |
742 | |
743 const char *t_strcut(const char *str, char cutchar) | |
744 { | |
745 const char *p; | |
746 | |
747 for (p = str; *p != '\0'; p++) { | |
748 if (*p == cutchar) | |
5
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
749 return t_strdup_until(str, p); |
0 | 750 } |
751 | |
752 return str; | |
753 } | |
754 | |
755 int is_numeric(const char *str, char end_char) | |
756 { | |
757 if (*str == '\0' || *str == end_char) | |
758 return FALSE; | |
759 | |
760 while (*str != '\0' && *str != end_char) { | |
761 if (!i_isdigit(*str)) | |
762 return FALSE; | |
763 str++; | |
764 } | |
765 | |
766 return TRUE; | |
767 } | |
768 | |
769 char *str_ucase(char *str) | |
770 { | |
771 char *p; | |
772 | |
773 for (p = str; *p != '\0'; p++) | |
774 *p = i_toupper(*p); | |
775 return str; | |
776 } | |
777 | |
778 char *str_lcase(char *str) | |
779 { | |
780 char *p; | |
781 | |
782 for (p = str; *p != '\0'; p++) | |
783 *p = i_tolower(*p); | |
784 return str; | |
785 } | |
786 | |
787 char *i_strtoken(char **str, char delim) | |
788 { | |
789 char *ret; | |
790 | |
791 if (*str == NULL || **str == '\0') | |
792 return NULL; | |
793 | |
794 ret = *str; | |
795 while (**str != '\0') { | |
796 if (**str == delim) { | |
797 **str = '\0'; | |
798 (*str)++; | |
799 break; | |
800 } | |
801 (*str)++; | |
802 } | |
803 return ret; | |
804 } | |
805 | |
806 void string_remove_escapes(char *str) | |
807 { | |
808 char *dest; | |
809 | |
810 for (dest = str; *str != '\0'; str++) { | |
811 if (*str != '\\' || str[1] == '\0') | |
812 *dest++ = *str; | |
813 } | |
814 | |
815 *dest = '\0'; | |
816 } | |
817 | |
818 int strarray_length(char *const array[]) | |
819 { | |
820 int len; | |
821 | |
822 len = 0; | |
823 while (*array) { | |
824 len++; | |
825 array++; | |
826 } | |
827 return len; | |
828 } | |
829 | |
830 int strarray_find(char *const array[], const char *item) | |
831 { | |
832 int index; | |
833 | |
834 i_assert(item != NULL); | |
835 | |
836 for (index = 0; *array != NULL; index++, array++) { | |
837 if (strcasecmp(*array, item) == 0) | |
838 return index; | |
839 } | |
840 | |
841 return -1; | |
842 } | |
843 | |
844 char *const *t_strsplit(const char *data, const char *separators) | |
845 { | |
846 const char **array; | |
847 char *str; | |
848 int alloc_len, len; | |
849 | |
850 i_assert(*separators != '\0'); | |
851 | |
852 str = (char *) t_strdup(data); | |
853 | |
854 alloc_len = 20; | |
855 array = t_buffer_get(sizeof(const char *) * alloc_len); | |
856 | |
857 array[0] = str; len = 1; | |
858 while (*str != '\0') { | |
859 if (strchr(separators, *str) != NULL) { | |
860 /* separator found */ | |
861 if (len+1 >= alloc_len) { | |
862 alloc_len *= 2; | |
863 array = t_buffer_reget(array, | |
864 sizeof(const char *) * | |
865 alloc_len); | |
866 } | |
867 | |
868 *str = '\0'; | |
869 array[len++] = str+1; | |
870 } | |
871 | |
872 str++; | |
873 } | |
874 array[len] = NULL; | |
875 | |
876 t_buffer_alloc(sizeof(const char *) * (len+1)); | |
877 return (char *const *) array; | |
878 } | |
879 | |
880 const char *t_strjoin_replace(char *const args[], char separator, | |
881 int replacearg, const char *replacedata) | |
882 { | |
883 const char *arg; | |
884 char *data; | |
885 unsigned int alloc_len, arg_len, full_len; | |
886 int i; | |
887 | |
888 if (args[0] == NULL) | |
889 return NULL; | |
890 | |
891 alloc_len = 512; full_len = 0; | |
892 data = t_buffer_get(alloc_len); | |
893 for (i = 0; args[i] != NULL; i++) { | |
894 arg = i == replacearg ? replacedata : args[i]; | |
895 arg_len = strlen(arg); | |
896 | |
897 if (full_len + arg_len+1 >= alloc_len) { | |
898 alloc_len = nearest_power(full_len + arg_len+1); | |
899 data = t_buffer_reget(data, alloc_len); | |
900 } | |
901 | |
902 memcpy(data+full_len, arg, arg_len); | |
903 full_len += arg_len; | |
904 | |
905 data[full_len++] = separator; | |
906 } | |
907 data[full_len-1] = '\0'; | |
908 | |
909 t_buffer_alloc(full_len); | |
910 return data; | |
911 } |