Mercurial > dovecot > core-2.2
annotate src/lib/strfuncs.c @ 482:d2303c38a7cf HEAD
Check vsnprintf() return values more carefully, thanks to Thomas Wouters
<thomas@xs4all.net> for noticing.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Wed, 23 Oct 2002 16:16:50 +0300 |
parents | c58fc0fd7894 |
children | 990dae663bc3 |
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 | |
183
4a7ab9e94f25
size_t fixes for lib/. Changed OFF_T_FORMAT to PRIuOFF_T which is more
Timo Sirainen <tss@iki.fi>
parents:
179
diff
changeset
|
36 typedef void *(*ALLOC_FUNC)(Pool, size_t); |
0 | 37 |
183
4a7ab9e94f25
size_t fixes for lib/. Changed OFF_T_FORMAT to PRIuOFF_T which is more
Timo Sirainen <tss@iki.fi>
parents:
179
diff
changeset
|
38 static void *tp_malloc(Pool pool __attr_unused__, size_t size) |
0 | 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; | |
464
c634b705f24b
Removed several useless handers of printf_string_upper_bound(), and added a
Timo Sirainen <tss@iki.fi>
parents:
451
diff
changeset
|
79 int mod_long, mod_extra_long; |
0 | 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 | |
183
4a7ab9e94f25
size_t fixes for lib/. Changed OFF_T_FORMAT to PRIuOFF_T which is more
Timo Sirainen <tss@iki.fi>
parents:
179
diff
changeset
|
88 size_t printf_string_upper_bound(const char *format, va_list args) |
0 | 89 { |
183
4a7ab9e94f25
size_t fixes for lib/. Changed OFF_T_FORMAT to PRIuOFF_T which is more
Timo Sirainen <tss@iki.fi>
parents:
179
diff
changeset
|
90 size_t len = 1; |
0 | 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 | |
107 memset(&spec, 0, sizeof(spec)); | |
108 do | |
109 { | |
110 c = *format++; | |
111 switch (c) | |
112 { | |
113 GDoubleIEEE754 u_double; | |
114 unsigned int v_uint; | |
115 int v_int; | |
116 const char *v_string; | |
117 | |
118 /* beware of positional parameters | |
119 */ | |
120 case '$': | |
451
af7b05f88dae
printf_string_upper_bound(): Instead of just warning we can't handle
Timo Sirainen <tss@iki.fi>
parents:
236
diff
changeset
|
121 i_panic("unable to handle positional parameters (%%n$)"); |
0 | 122 break; |
123 | |
124 /* parse flags | |
125 */ | |
126 case '#': | |
127 spec.alternate_format = TRUE; | |
128 break; | |
129 case '0': | |
130 spec.zero_padding = TRUE; | |
131 break; | |
132 case '-': | |
133 spec.adjust_left = TRUE; | |
134 break; | |
135 case ' ': | |
136 spec.add_space = TRUE; | |
137 break; | |
138 case '+': | |
139 spec.add_sign = TRUE; | |
140 break; | |
141 case '\'': | |
142 spec.locale_grouping = TRUE; | |
143 break; | |
144 | |
145 /* parse output size specifications | |
146 */ | |
147 case '.': | |
148 spec.seen_precision = TRUE; | |
149 break; | |
150 case '1': | |
151 case '2': | |
152 case '3': | |
153 case '4': | |
154 case '5': | |
155 case '6': | |
156 case '7': | |
157 case '8': | |
158 case '9': | |
159 v_uint = c - '0'; | |
160 c = *format; | |
161 while (c >= '0' && c <= '9') | |
162 { | |
163 format++; | |
50
d493b9cc265e
Introduced uoff_t which is the unsigned-equilevant of off_t. This was needed
Timo Sirainen <tss@iki.fi>
parents:
8
diff
changeset
|
164 v_uint = v_uint * 10 + (c - '0'); |
0 | 165 c = *format; |
166 } | |
167 if (spec.seen_precision) | |
168 spec.precision = I_MAX (spec.precision, v_uint); | |
169 else | |
170 spec.min_width = I_MAX (spec.min_width, v_uint); | |
171 break; | |
172 case '*': | |
173 v_int = va_arg (args, int); | |
174 if (spec.seen_precision) | |
175 { | |
176 /* forget about negative precision */ | |
177 if (v_int >= 0) | |
178 spec.precision = I_MAX ((int)spec.precision, v_int); | |
179 } | |
180 else | |
181 { | |
182 if (v_int < 0) | |
183 { | |
184 v_int = - v_int; | |
185 spec.adjust_left = TRUE; | |
186 } | |
187 spec.min_width = I_MAX ((int)spec.min_width, v_int); | |
188 } | |
189 break; | |
190 | |
191 /* parse type modifiers | |
192 */ | |
193 case 'h': | |
464
c634b705f24b
Removed several useless handers of printf_string_upper_bound(), and added a
Timo Sirainen <tss@iki.fi>
parents:
451
diff
changeset
|
194 /* ignore */ |
0 | 195 break; |
196 case 'l': | |
197 if (!seen_l) | |
198 { | |
199 spec.mod_long = TRUE; | |
200 seen_l = TRUE; | |
201 break; | |
202 } | |
203 /* else, fall through */ | |
204 case 'L': | |
205 spec.mod_long = TRUE; | |
206 spec.mod_extra_long = TRUE; | |
207 break; | |
208 | |
209 /* parse output conversions | |
210 */ | |
211 case '%': | |
212 conv_len += 1; | |
213 break; | |
214 case 'o': | |
215 conv_len += 2; | |
216 /* fall through */ | |
217 case 'd': | |
218 case 'i': | |
219 conv_len += 1; /* sign */ | |
220 /* fall through */ | |
221 case 'u': | |
222 conv_len += 4; | |
223 /* fall through */ | |
224 case 'x': | |
225 case 'X': | |
226 spec.possible_sign = TRUE; | |
227 conv_len += 10; | |
228 if (spec.mod_long && HONOUR_LONGS) | |
229 conv_len *= 2; | |
230 if (spec.mod_extra_long) | |
231 conv_len *= 2; | |
232 if (spec.mod_extra_long) | |
233 { | |
464
c634b705f24b
Removed several useless handers of printf_string_upper_bound(), and added a
Timo Sirainen <tss@iki.fi>
parents:
451
diff
changeset
|
234 #if SIZEOF_LONG_LONG > 0 |
c634b705f24b
Removed several useless handers of printf_string_upper_bound(), and added a
Timo Sirainen <tss@iki.fi>
parents:
451
diff
changeset
|
235 (void) va_arg (args, long long); |
0 | 236 #else |
466
c58fc0fd7894
Fail if %ll is used and we don't have long long.
Timo Sirainen <tss@iki.fi>
parents:
464
diff
changeset
|
237 i_panic("mod_extra_long not supported"); |
0 | 238 #endif |
239 } | |
240 else if (spec.mod_long) | |
241 (void) va_arg (args, long); | |
242 else | |
243 (void) va_arg (args, int); | |
244 break; | |
245 case 'A': | |
246 case 'a': | |
247 /* 0x */ | |
248 conv_len += 2; | |
249 /* fall through */ | |
250 case 'g': | |
251 case 'G': | |
252 case 'e': | |
253 case 'E': | |
254 case 'f': | |
255 spec.possible_sign = TRUE; | |
256 /* n . dddddddddddddddddddddddd E +- eeee */ | |
257 conv_len += 1 + 1 + I_MAX (24, spec.precision) + 1 + 1 + 4; | |
258 if (spec.mod_extra_long) | |
451
af7b05f88dae
printf_string_upper_bound(): Instead of just warning we can't handle
Timo Sirainen <tss@iki.fi>
parents:
236
diff
changeset
|
259 i_panic("unable to handle long double"); |
0 | 260 #ifdef HAVE_LONG_DOUBLE |
261 #error need to implement special handling for long double | |
262 #endif | |
263 u_double.v_double = va_arg (args, double); | |
264 /* %f can expand up to all significant digits before '.' (308) */ | |
265 if (c == 'f' && | |
266 u_double.mpn.biased_exponent > 0 && u_double.mpn.biased_exponent < 2047) | |
267 { | |
268 int exp = u_double.mpn.biased_exponent; | |
269 | |
270 exp -= G_IEEE754_DOUBLE_BIAS; | |
271 exp = exp * G_LOG_2_BASE_10 + 1; | |
272 conv_len += exp; | |
273 } | |
274 /* some printf() implementations require extra padding for rounding */ | |
275 conv_len += 2; | |
276 /* we can't really handle locale specific grouping here */ | |
277 if (spec.locale_grouping) | |
278 conv_len *= 2; | |
279 break; | |
280 case 'c': | |
281 conv_len += spec.mod_long ? MB_LEN_MAX : 1; | |
282 (void) va_arg (args, int); | |
283 break; | |
284 case 's': | |
285 v_string = va_arg (args, char*); | |
286 if (!v_string) | |
287 conv_len += 8; /* hold "(null)" */ | |
288 else if (spec.seen_precision) | |
289 conv_len += spec.precision; | |
290 else | |
291 conv_len += strlen (v_string); | |
292 conv_done = TRUE; | |
293 if (spec.mod_long) | |
451
af7b05f88dae
printf_string_upper_bound(): Instead of just warning we can't handle
Timo Sirainen <tss@iki.fi>
parents:
236
diff
changeset
|
294 i_panic("unable to handle wide char strings"); |
0 | 295 break; |
296 case 'p': | |
297 spec.alternate_format = TRUE; | |
298 conv_len += 10; | |
299 if (HONOUR_LONGS) | |
300 conv_len *= 2; | |
464
c634b705f24b
Removed several useless handers of printf_string_upper_bound(), and added a
Timo Sirainen <tss@iki.fi>
parents:
451
diff
changeset
|
301 conv_done = TRUE; |
c634b705f24b
Removed several useless handers of printf_string_upper_bound(), and added a
Timo Sirainen <tss@iki.fi>
parents:
451
diff
changeset
|
302 (void) va_arg (args, void*); |
0 | 303 break; |
304 | |
305 /* handle invalid cases | |
306 */ | |
307 case '\000': | |
308 /* no conversion specification, bad bad */ | |
464
c634b705f24b
Removed several useless handers of printf_string_upper_bound(), and added a
Timo Sirainen <tss@iki.fi>
parents:
451
diff
changeset
|
309 i_panic("Missing conversion specifier"); |
0 | 310 break; |
311 default: | |
451
af7b05f88dae
printf_string_upper_bound(): Instead of just warning we can't handle
Timo Sirainen <tss@iki.fi>
parents:
236
diff
changeset
|
312 i_panic("unable to handle `%c' while parsing format", c); |
0 | 313 break; |
314 } | |
315 conv_done |= conv_len > 0; | |
316 } | |
317 while (!conv_done); | |
318 /* handle width specifications */ | |
319 conv_len = I_MAX (conv_len, I_MAX (spec.precision, spec.min_width)); | |
320 /* handle flags */ | |
321 conv_len += spec.alternate_format ? 2 : 0; | |
322 conv_len += (spec.add_space || spec.add_sign || spec.possible_sign); | |
323 /* finally done */ | |
324 len += conv_len; | |
325 } /* else (c == '%') */ | |
326 } /* while (*format) */ | |
327 | |
328 return len; | |
329 } | |
330 | |
331 static const char *fix_format_real(const char *fmt, const char *p) | |
332 { | |
333 const char *errstr; | |
334 char *buf; | |
183
4a7ab9e94f25
size_t fixes for lib/. Changed OFF_T_FORMAT to PRIuOFF_T which is more
Timo Sirainen <tss@iki.fi>
parents:
179
diff
changeset
|
335 size_t pos, alloc, errlen; |
0 | 336 |
337 errstr = strerror(errno); | |
338 errlen = strlen(errstr); | |
339 | |
183
4a7ab9e94f25
size_t fixes for lib/. Changed OFF_T_FORMAT to PRIuOFF_T which is more
Timo Sirainen <tss@iki.fi>
parents:
179
diff
changeset
|
340 pos = (size_t) (p-fmt); |
4a7ab9e94f25
size_t fixes for lib/. Changed OFF_T_FORMAT to PRIuOFF_T which is more
Timo Sirainen <tss@iki.fi>
parents:
179
diff
changeset
|
341 i_assert(pos < SSIZE_T_MAX); |
0 | 342 |
343 alloc = pos + errlen + 128; | |
344 buf = t_buffer_get(alloc); | |
345 | |
346 memcpy(buf, fmt, pos); | |
347 | |
348 while (*p != '\0') { | |
349 if (*p == '%' && p[1] == 'm') { | |
350 if (pos+errlen+1 > alloc) { | |
351 alloc += errlen+1 + 128; | |
352 buf = t_buffer_get(alloc); | |
353 } | |
354 | |
355 memcpy(buf+pos, errstr, errlen); | |
356 pos += errlen; | |
357 p += 2; | |
358 } else { | |
359 /* p + \0 */ | |
360 if (pos+2 > alloc) { | |
361 alloc += 128; | |
362 buf = t_buffer_get(alloc); | |
363 } | |
364 | |
365 buf[pos++] = *p; | |
366 p++; | |
367 } | |
368 } | |
369 | |
370 buf[pos++] = '\0'; | |
371 t_buffer_alloc(pos); | |
372 return buf; | |
373 } | |
374 | |
375 /* replace %m with strerror() */ | |
376 static const char *fix_format(const char *fmt) | |
377 { | |
378 const char *p; | |
379 | |
380 for (p = fmt; *p != '\0'; p++) { | |
381 if (*p == '%' && p[1] == 'm') | |
382 return fix_format_real(fmt, p); | |
383 } | |
384 | |
385 return fmt; | |
386 } | |
387 | |
183
4a7ab9e94f25
size_t fixes for lib/. Changed OFF_T_FORMAT to PRIuOFF_T which is more
Timo Sirainen <tss@iki.fi>
parents:
179
diff
changeset
|
388 int i_snprintf(char *str, size_t max_chars, const char *format, ...) |
0 | 389 { |
390 #ifdef HAVE_VSNPRINTF | |
391 va_list args; | |
392 int ret; | |
393 | |
394 i_assert(str != NULL); | |
183
4a7ab9e94f25
size_t fixes for lib/. Changed OFF_T_FORMAT to PRIuOFF_T which is more
Timo Sirainen <tss@iki.fi>
parents:
179
diff
changeset
|
395 i_assert(max_chars < SSIZE_T_MAX); |
0 | 396 i_assert(format != NULL); |
397 | |
233
3f92df43cfa7
t_push()/t_pop() around various *sprintf() functions, so "%m" format won't
Timo Sirainen <tss@iki.fi>
parents:
183
diff
changeset
|
398 t_push(); |
0 | 399 va_start(args, format); |
400 ret = vsnprintf(str, max_chars, fix_format(format), args); | |
401 va_end(args); | |
233
3f92df43cfa7
t_push()/t_pop() around various *sprintf() functions, so "%m" format won't
Timo Sirainen <tss@iki.fi>
parents:
183
diff
changeset
|
402 t_pop(); |
0 | 403 |
482
d2303c38a7cf
Check vsnprintf() return values more carefully, thanks to Thomas Wouters
Timo Sirainen <tss@iki.fi>
parents:
466
diff
changeset
|
404 if (ret < 0 || (size_t)ret >= max_chars) { |
0 | 405 str[max_chars-1] = '\0'; |
406 ret = strlen(str); | |
407 } | |
408 | |
409 return ret; | |
410 #else | |
411 char *buf; | |
412 va_list args; | |
413 int len; | |
414 | |
415 i_assert(str != NULL); | |
183
4a7ab9e94f25
size_t fixes for lib/. Changed OFF_T_FORMAT to PRIuOFF_T which is more
Timo Sirainen <tss@iki.fi>
parents:
179
diff
changeset
|
416 i_assert(max_chars < SSIZE_T_MAX); |
0 | 417 i_assert(format != NULL); |
418 | |
233
3f92df43cfa7
t_push()/t_pop() around various *sprintf() functions, so "%m" format won't
Timo Sirainen <tss@iki.fi>
parents:
183
diff
changeset
|
419 t_push(); |
236
400ac5f9ed40
previous t_push()/t_pop() changes break things. fixed :)
Timo Sirainen <tss@iki.fi>
parents:
233
diff
changeset
|
420 |
0 | 421 va_start(args, format); |
422 format = fix_format(format); | |
423 buf = t_buffer_get(printf_string_upper_bound(format, args)); | |
424 va_end(args); | |
425 | |
426 len = vsprintf(buf, format, args); | |
427 if (len >= (int)max_chars) | |
428 len = max_chars-1; | |
429 | |
430 memcpy(str, buf, len); | |
431 str[len] = '\0'; | |
236
400ac5f9ed40
previous t_push()/t_pop() changes break things. fixed :)
Timo Sirainen <tss@iki.fi>
parents:
233
diff
changeset
|
432 |
400ac5f9ed40
previous t_push()/t_pop() changes break things. fixed :)
Timo Sirainen <tss@iki.fi>
parents:
233
diff
changeset
|
433 t_pop(); |
0 | 434 return len; |
435 #endif | |
436 } | |
437 | |
438 #define STRDUP_CORE(alloc_func, str) STMT_START { \ | |
439 void *mem; \ | |
183
4a7ab9e94f25
size_t fixes for lib/. Changed OFF_T_FORMAT to PRIuOFF_T which is more
Timo Sirainen <tss@iki.fi>
parents:
179
diff
changeset
|
440 size_t len; \ |
0 | 441 \ |
442 for (len = 0; (str)[len] != '\0'; ) \ | |
443 len++; \ | |
444 len++; \ | |
445 mem = alloc_func; \ | |
446 memcpy(mem, str, sizeof(str[0])*len); \ | |
447 return mem; \ | |
448 } STMT_END | |
449 | |
450 char *p_strdup(Pool pool, const char *str) | |
451 { | |
452 if (str == NULL) | |
453 return NULL; | |
454 | |
455 STRDUP_CORE(p_malloc(pool, len), str); | |
456 } | |
457 | |
458 const char *t_strdup(const char *str) | |
459 { | |
460 if (str == NULL) | |
461 return NULL; | |
462 | |
463 STRDUP_CORE(t_malloc(len), str); | |
464 } | |
465 | |
64
83ae914a583a
added t_strdup_noconst() which can be used instead of (char *) t_strdup().
Timo Sirainen <tss@iki.fi>
parents:
63
diff
changeset
|
466 char *t_strdup_noconst(const char *str) |
83ae914a583a
added t_strdup_noconst() which can be used instead of (char *) t_strdup().
Timo Sirainen <tss@iki.fi>
parents:
63
diff
changeset
|
467 { |
83ae914a583a
added t_strdup_noconst() which can be used instead of (char *) t_strdup().
Timo Sirainen <tss@iki.fi>
parents:
63
diff
changeset
|
468 if (str == NULL) |
83ae914a583a
added t_strdup_noconst() which can be used instead of (char *) t_strdup().
Timo Sirainen <tss@iki.fi>
parents:
63
diff
changeset
|
469 return NULL; |
83ae914a583a
added t_strdup_noconst() which can be used instead of (char *) t_strdup().
Timo Sirainen <tss@iki.fi>
parents:
63
diff
changeset
|
470 |
83ae914a583a
added t_strdup_noconst() which can be used instead of (char *) t_strdup().
Timo Sirainen <tss@iki.fi>
parents:
63
diff
changeset
|
471 STRDUP_CORE(t_malloc(len), str); |
83ae914a583a
added t_strdup_noconst() which can be used instead of (char *) t_strdup().
Timo Sirainen <tss@iki.fi>
parents:
63
diff
changeset
|
472 } |
83ae914a583a
added t_strdup_noconst() which can be used instead of (char *) t_strdup().
Timo Sirainen <tss@iki.fi>
parents:
63
diff
changeset
|
473 |
0 | 474 int *p_intarrdup(Pool pool, const int *arr) |
475 { | |
476 if (arr == NULL) | |
477 return NULL; | |
478 | |
479 STRDUP_CORE(p_malloc(pool, sizeof(int) * len), arr); | |
480 } | |
481 | |
482 const int *t_intarrdup(const int *arr) | |
483 { | |
484 if (arr == NULL) | |
485 return NULL; | |
486 | |
487 STRDUP_CORE(t_malloc(sizeof(int) * len), arr); | |
488 } | |
489 | |
490 #define STRDUP_EMPTY_CORE(alloc_func, str) STMT_START { \ | |
491 if ((str) == NULL || (str)[0] == '\0') \ | |
492 return NULL; \ | |
493 \ | |
494 STRDUP_CORE(alloc_func, str); \ | |
495 } STMT_END | |
496 | |
497 | |
498 char *p_strdup_empty(Pool pool, const char *str) | |
499 { | |
500 STRDUP_EMPTY_CORE(p_malloc(pool, len), str); | |
501 } | |
502 | |
503 const char *t_strdup_empty(const char *str) | |
504 { | |
505 STRDUP_EMPTY_CORE(t_malloc(len), str); | |
506 } | |
507 | |
5
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
508 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
|
509 { |
183
4a7ab9e94f25
size_t fixes for lib/. Changed OFF_T_FORMAT to PRIuOFF_T which is more
Timo Sirainen <tss@iki.fi>
parents:
179
diff
changeset
|
510 size_t size; |
5
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
511 char *mem; |
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
512 |
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
513 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
|
514 |
183
4a7ab9e94f25
size_t fixes for lib/. Changed OFF_T_FORMAT to PRIuOFF_T which is more
Timo Sirainen <tss@iki.fi>
parents:
179
diff
changeset
|
515 size = (size_t) (end-start); |
4a7ab9e94f25
size_t fixes for lib/. Changed OFF_T_FORMAT to PRIuOFF_T which is more
Timo Sirainen <tss@iki.fi>
parents:
179
diff
changeset
|
516 i_assert(size < SSIZE_T_MAX); |
8 | 517 |
518 mem = p_malloc(pool, size + 1); | |
5
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
519 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
|
520 return mem; |
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
521 } |
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
522 |
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
523 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
|
524 { |
183
4a7ab9e94f25
size_t fixes for lib/. Changed OFF_T_FORMAT to PRIuOFF_T which is more
Timo Sirainen <tss@iki.fi>
parents:
179
diff
changeset
|
525 size_t size; |
5
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
526 char *mem; |
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
527 |
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
528 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
|
529 |
183
4a7ab9e94f25
size_t fixes for lib/. Changed OFF_T_FORMAT to PRIuOFF_T which is more
Timo Sirainen <tss@iki.fi>
parents:
179
diff
changeset
|
530 size = (size_t) (end-start); |
4a7ab9e94f25
size_t fixes for lib/. Changed OFF_T_FORMAT to PRIuOFF_T which is more
Timo Sirainen <tss@iki.fi>
parents:
179
diff
changeset
|
531 i_assert(size < SSIZE_T_MAX); |
8 | 532 |
533 mem = t_malloc(size + 1); | |
5
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
534 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
|
535 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
|
536 return mem; |
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
537 } |
1b34ec11fff8
Message data is parsed in blocks (no longer entirely mmap()ed). Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
538 |
183
4a7ab9e94f25
size_t fixes for lib/. Changed OFF_T_FORMAT to PRIuOFF_T which is more
Timo Sirainen <tss@iki.fi>
parents:
179
diff
changeset
|
539 static inline char *strndup_core(const char *str, size_t max_chars, |
4a7ab9e94f25
size_t fixes for lib/. Changed OFF_T_FORMAT to PRIuOFF_T which is more
Timo Sirainen <tss@iki.fi>
parents:
179
diff
changeset
|
540 ALLOC_FUNC alloc, Pool pool) |
0 | 541 { |
542 char *mem; | |
183
4a7ab9e94f25
size_t fixes for lib/. Changed OFF_T_FORMAT to PRIuOFF_T which is more
Timo Sirainen <tss@iki.fi>
parents:
179
diff
changeset
|
543 size_t len; |
0 | 544 |
183
4a7ab9e94f25
size_t fixes for lib/. Changed OFF_T_FORMAT to PRIuOFF_T which is more
Timo Sirainen <tss@iki.fi>
parents:
179
diff
changeset
|
545 i_assert(max_chars < SSIZE_T_MAX); |
0 | 546 |
547 if (str == NULL) | |
548 return NULL; | |
549 | |
550 len = 0; | |
551 while (str[len] != '\0' && len < max_chars) | |
552 len++; | |
553 | |
554 mem = alloc(pool, len+1); | |
555 memcpy(mem, str, len); | |
556 mem[len] = '\0'; | |
557 return mem; | |
558 } | |
559 | |
183
4a7ab9e94f25
size_t fixes for lib/. Changed OFF_T_FORMAT to PRIuOFF_T which is more
Timo Sirainen <tss@iki.fi>
parents:
179
diff
changeset
|
560 char *p_strndup(Pool pool, const char *str, size_t max_chars) |
0 | 561 { |
562 return strndup_core(str, max_chars, pool->malloc, pool); | |
563 } | |
564 | |
183
4a7ab9e94f25
size_t fixes for lib/. Changed OFF_T_FORMAT to PRIuOFF_T which is more
Timo Sirainen <tss@iki.fi>
parents:
179
diff
changeset
|
565 const char *t_strndup(const char *str, size_t max_chars) |
0 | 566 { |
567 return strndup_core(str, max_chars, tp_malloc, NULL); | |
568 } | |
569 | |
570 char *p_strdup_printf(Pool pool, const char *format, ...) | |
571 { | |
572 va_list args; | |
573 char *ret; | |
574 | |
575 va_start(args, format); | |
576 ret = p_strdup_vprintf(pool, format, args); | |
577 va_end(args); | |
578 | |
579 return ret; | |
580 } | |
581 | |
582 const char *t_strdup_printf(const char *format, ...) | |
583 { | |
584 va_list args; | |
585 const char *ret; | |
586 | |
587 va_start(args, format); | |
588 ret = t_strdup_vprintf(format, args); | |
589 va_end(args); | |
590 | |
591 return ret; | |
592 } | |
593 | |
594 static inline char * | |
595 strdup_vprintf_core(const char *format, va_list args, | |
596 ALLOC_FUNC alloc_func, Pool pool) | |
597 { | |
598 va_list temp_args; | |
599 char *ret; | |
600 | |
601 if (format == NULL) | |
602 return NULL; | |
233
3f92df43cfa7
t_push()/t_pop() around various *sprintf() functions, so "%m" format won't
Timo Sirainen <tss@iki.fi>
parents:
183
diff
changeset
|
603 |
0 | 604 format = fix_format(format); |
605 | |
606 VA_COPY(temp_args, args); | |
607 | |
608 ret = alloc_func(pool, printf_string_upper_bound(format, args)); | |
609 vsprintf(ret, format, args); | |
610 | |
611 va_end(temp_args); | |
612 | |
613 return ret; | |
614 } | |
615 | |
616 char *p_strdup_vprintf(Pool pool, const char *format, va_list args) | |
617 { | |
236
400ac5f9ed40
previous t_push()/t_pop() changes break things. fixed :)
Timo Sirainen <tss@iki.fi>
parents:
233
diff
changeset
|
618 char *ret; |
400ac5f9ed40
previous t_push()/t_pop() changes break things. fixed :)
Timo Sirainen <tss@iki.fi>
parents:
233
diff
changeset
|
619 |
400ac5f9ed40
previous t_push()/t_pop() changes break things. fixed :)
Timo Sirainen <tss@iki.fi>
parents:
233
diff
changeset
|
620 t_push(); |
400ac5f9ed40
previous t_push()/t_pop() changes break things. fixed :)
Timo Sirainen <tss@iki.fi>
parents:
233
diff
changeset
|
621 ret = strdup_vprintf_core(format, args, pool->malloc, pool); |
400ac5f9ed40
previous t_push()/t_pop() changes break things. fixed :)
Timo Sirainen <tss@iki.fi>
parents:
233
diff
changeset
|
622 t_pop(); |
400ac5f9ed40
previous t_push()/t_pop() changes break things. fixed :)
Timo Sirainen <tss@iki.fi>
parents:
233
diff
changeset
|
623 return ret; |
0 | 624 } |
625 | |
626 const char *t_strdup_vprintf(const char *format, va_list args) | |
627 { | |
628 return strdup_vprintf_core(format, args, tp_malloc, NULL); | |
629 } | |
630 | |
631 void p_strdup_replace(Pool pool, char **dest, const char *str) | |
632 { | |
633 p_free(pool, *dest); | |
634 *dest = p_strdup(pool, str); | |
635 } | |
636 | |
637 const char *temp_strconcat(const char *str1, va_list args, | |
183
4a7ab9e94f25
size_t fixes for lib/. Changed OFF_T_FORMAT to PRIuOFF_T which is more
Timo Sirainen <tss@iki.fi>
parents:
179
diff
changeset
|
638 size_t *ret_len) |
0 | 639 { |
640 const char *str; | |
641 char *temp; | |
183
4a7ab9e94f25
size_t fixes for lib/. Changed OFF_T_FORMAT to PRIuOFF_T which is more
Timo Sirainen <tss@iki.fi>
parents:
179
diff
changeset
|
642 size_t full_len, len, bufsize; |
0 | 643 |
644 if (str1 == NULL) | |
645 return NULL; | |
646 | |
647 /* put str1 to buffer */ | |
648 len = strlen(str1); | |
649 bufsize = len <= STRCONCAT_BUFSIZE ? STRCONCAT_BUFSIZE : | |
650 nearest_power(len+1); | |
651 temp = t_buffer_get(bufsize); | |
652 | |
653 memcpy(temp, str1, len); | |
654 full_len = len; | |
655 | |
656 /* put rest of the strings to buffer */ | |
657 while ((str = va_arg(args, char *)) != NULL) { | |
658 len = strlen(str); | |
659 if (len == 0) | |
660 continue; | |
661 | |
662 if (bufsize < full_len+len+1) { | |
663 bufsize = nearest_power(bufsize+len+1); | |
664 temp = t_buffer_reget(temp, bufsize); | |
665 } | |
666 | |
667 memcpy(temp+full_len, str, len); | |
668 full_len += len; | |
669 } | |
670 | |
671 temp[full_len] = '\0'; | |
672 *ret_len = full_len+1; | |
673 return temp; | |
674 } | |
675 | |
676 char *p_strconcat(Pool pool, const char *str1, ...) | |
677 { | |
678 va_list args; | |
679 const char *temp; | |
680 char *ret; | |
183
4a7ab9e94f25
size_t fixes for lib/. Changed OFF_T_FORMAT to PRIuOFF_T which is more
Timo Sirainen <tss@iki.fi>
parents:
179
diff
changeset
|
681 size_t len; |
0 | 682 |
683 va_start(args, str1); | |
684 | |
685 temp = temp_strconcat(str1, args, &len); | |
686 if (temp == NULL) | |
687 ret = NULL; | |
688 else { | |
689 ret = p_malloc(pool, len); | |
690 memcpy(ret, temp, len); | |
691 } | |
692 | |
693 va_end(args); | |
694 return ret; | |
695 } | |
696 | |
697 const char *t_strconcat(const char *str1, ...) | |
698 { | |
699 va_list args; | |
700 const char *ret; | |
183
4a7ab9e94f25
size_t fixes for lib/. Changed OFF_T_FORMAT to PRIuOFF_T which is more
Timo Sirainen <tss@iki.fi>
parents:
179
diff
changeset
|
701 size_t len; |
0 | 702 |
703 va_start(args, str1); | |
704 | |
705 ret = temp_strconcat(str1, args, &len); | |
706 if (ret != NULL) | |
707 t_buffer_alloc(len); | |
708 | |
709 va_end(args); | |
710 return ret; | |
711 } | |
712 | |
713 const char *t_strcut(const char *str, char cutchar) | |
714 { | |
715 const char *p; | |
716 | |
717 for (p = str; *p != '\0'; p++) { | |
718 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
|
719 return t_strdup_until(str, p); |
0 | 720 } |
721 | |
722 return str; | |
723 } | |
724 | |
725 int is_numeric(const char *str, char end_char) | |
726 { | |
727 if (*str == '\0' || *str == end_char) | |
728 return FALSE; | |
729 | |
730 while (*str != '\0' && *str != end_char) { | |
731 if (!i_isdigit(*str)) | |
732 return FALSE; | |
733 str++; | |
734 } | |
735 | |
736 return TRUE; | |
737 } | |
738 | |
739 char *str_ucase(char *str) | |
740 { | |
741 char *p; | |
742 | |
743 for (p = str; *p != '\0'; p++) | |
744 *p = i_toupper(*p); | |
745 return str; | |
746 } | |
747 | |
748 char *str_lcase(char *str) | |
749 { | |
750 char *p; | |
751 | |
752 for (p = str; *p != '\0'; p++) | |
753 *p = i_tolower(*p); | |
754 return str; | |
755 } | |
756 | |
757 char *i_strtoken(char **str, char delim) | |
758 { | |
759 char *ret; | |
760 | |
761 if (*str == NULL || **str == '\0') | |
762 return NULL; | |
763 | |
764 ret = *str; | |
765 while (**str != '\0') { | |
766 if (**str == delim) { | |
767 **str = '\0'; | |
768 (*str)++; | |
769 break; | |
770 } | |
771 (*str)++; | |
772 } | |
773 return ret; | |
774 } | |
775 | |
776 void string_remove_escapes(char *str) | |
777 { | |
778 char *dest; | |
779 | |
780 for (dest = str; *str != '\0'; str++) { | |
781 if (*str != '\\' || str[1] == '\0') | |
782 *dest++ = *str; | |
783 } | |
784 | |
785 *dest = '\0'; | |
786 } | |
787 | |
788 int strarray_length(char *const array[]) | |
789 { | |
790 int len; | |
791 | |
792 len = 0; | |
793 while (*array) { | |
794 len++; | |
795 array++; | |
796 } | |
797 return len; | |
798 } | |
799 | |
800 int strarray_find(char *const array[], const char *item) | |
801 { | |
802 int index; | |
803 | |
804 i_assert(item != NULL); | |
805 | |
806 for (index = 0; *array != NULL; index++, array++) { | |
807 if (strcasecmp(*array, item) == 0) | |
808 return index; | |
809 } | |
810 | |
811 return -1; | |
812 } | |
813 | |
814 char *const *t_strsplit(const char *data, const char *separators) | |
815 { | |
64
83ae914a583a
added t_strdup_noconst() which can be used instead of (char *) t_strdup().
Timo Sirainen <tss@iki.fi>
parents:
63
diff
changeset
|
816 char **array; |
0 | 817 char *str; |
183
4a7ab9e94f25
size_t fixes for lib/. Changed OFF_T_FORMAT to PRIuOFF_T which is more
Timo Sirainen <tss@iki.fi>
parents:
179
diff
changeset
|
818 size_t alloc_len, len; |
0 | 819 |
820 i_assert(*separators != '\0'); | |
821 | |
68 | 822 len = strlen(data)+1; |
63 | 823 str = t_malloc(len); |
824 memcpy(str, data, len); | |
0 | 825 |
826 alloc_len = 20; | |
827 array = t_buffer_get(sizeof(const char *) * alloc_len); | |
828 | |
829 array[0] = str; len = 1; | |
830 while (*str != '\0') { | |
831 if (strchr(separators, *str) != NULL) { | |
832 /* separator found */ | |
833 if (len+1 >= alloc_len) { | |
834 alloc_len *= 2; | |
835 array = t_buffer_reget(array, | |
836 sizeof(const char *) * | |
837 alloc_len); | |
838 } | |
839 | |
840 *str = '\0'; | |
841 array[len++] = str+1; | |
842 } | |
843 | |
844 str++; | |
845 } | |
846 array[len] = NULL; | |
847 | |
848 t_buffer_alloc(sizeof(const char *) * (len+1)); | |
849 return (char *const *) array; | |
850 } | |
851 | |
852 const char *t_strjoin_replace(char *const args[], char separator, | |
853 int replacearg, const char *replacedata) | |
854 { | |
855 const char *arg; | |
856 char *data; | |
183
4a7ab9e94f25
size_t fixes for lib/. Changed OFF_T_FORMAT to PRIuOFF_T which is more
Timo Sirainen <tss@iki.fi>
parents:
179
diff
changeset
|
857 size_t alloc_len, arg_len, full_len; |
0 | 858 int i; |
859 | |
860 if (args[0] == NULL) | |
861 return NULL; | |
862 | |
863 alloc_len = 512; full_len = 0; | |
864 data = t_buffer_get(alloc_len); | |
865 for (i = 0; args[i] != NULL; i++) { | |
866 arg = i == replacearg ? replacedata : args[i]; | |
867 arg_len = strlen(arg); | |
868 | |
869 if (full_len + arg_len+1 >= alloc_len) { | |
870 alloc_len = nearest_power(full_len + arg_len+1); | |
871 data = t_buffer_reget(data, alloc_len); | |
872 } | |
873 | |
874 memcpy(data+full_len, arg, arg_len); | |
875 full_len += arg_len; | |
876 | |
877 data[full_len++] = separator; | |
878 } | |
879 data[full_len-1] = '\0'; | |
880 | |
881 t_buffer_alloc(full_len); | |
882 return data; | |
883 } | |
179
0ffecd4e7e1a
added dec2str() function and largest_t type, removed itoa() and ltoa()
Timo Sirainen <tss@iki.fi>
parents:
68
diff
changeset
|
884 |
0ffecd4e7e1a
added dec2str() function and largest_t type, removed itoa() and ltoa()
Timo Sirainen <tss@iki.fi>
parents:
68
diff
changeset
|
885 static size_t dec2str_recurse(char *buffer, size_t pos, size_t size, |
0ffecd4e7e1a
added dec2str() function and largest_t type, removed itoa() and ltoa()
Timo Sirainen <tss@iki.fi>
parents:
68
diff
changeset
|
886 largest_t number) |
0ffecd4e7e1a
added dec2str() function and largest_t type, removed itoa() and ltoa()
Timo Sirainen <tss@iki.fi>
parents:
68
diff
changeset
|
887 { |
0ffecd4e7e1a
added dec2str() function and largest_t type, removed itoa() and ltoa()
Timo Sirainen <tss@iki.fi>
parents:
68
diff
changeset
|
888 if (number == 0) |
0ffecd4e7e1a
added dec2str() function and largest_t type, removed itoa() and ltoa()
Timo Sirainen <tss@iki.fi>
parents:
68
diff
changeset
|
889 return 0; |
0ffecd4e7e1a
added dec2str() function and largest_t type, removed itoa() and ltoa()
Timo Sirainen <tss@iki.fi>
parents:
68
diff
changeset
|
890 |
0ffecd4e7e1a
added dec2str() function and largest_t type, removed itoa() and ltoa()
Timo Sirainen <tss@iki.fi>
parents:
68
diff
changeset
|
891 pos = dec2str_recurse(buffer, pos, size-1, number / 10); |
0ffecd4e7e1a
added dec2str() function and largest_t type, removed itoa() and ltoa()
Timo Sirainen <tss@iki.fi>
parents:
68
diff
changeset
|
892 if (pos < size) |
0ffecd4e7e1a
added dec2str() function and largest_t type, removed itoa() and ltoa()
Timo Sirainen <tss@iki.fi>
parents:
68
diff
changeset
|
893 buffer[pos] = '0' + (number % 10); |
0ffecd4e7e1a
added dec2str() function and largest_t type, removed itoa() and ltoa()
Timo Sirainen <tss@iki.fi>
parents:
68
diff
changeset
|
894 return pos + 1; |
0ffecd4e7e1a
added dec2str() function and largest_t type, removed itoa() and ltoa()
Timo Sirainen <tss@iki.fi>
parents:
68
diff
changeset
|
895 } |
0ffecd4e7e1a
added dec2str() function and largest_t type, removed itoa() and ltoa()
Timo Sirainen <tss@iki.fi>
parents:
68
diff
changeset
|
896 |
0ffecd4e7e1a
added dec2str() function and largest_t type, removed itoa() and ltoa()
Timo Sirainen <tss@iki.fi>
parents:
68
diff
changeset
|
897 void dec2str(char *buffer, size_t size, largest_t number) |
0ffecd4e7e1a
added dec2str() function and largest_t type, removed itoa() and ltoa()
Timo Sirainen <tss@iki.fi>
parents:
68
diff
changeset
|
898 { |
0ffecd4e7e1a
added dec2str() function and largest_t type, removed itoa() and ltoa()
Timo Sirainen <tss@iki.fi>
parents:
68
diff
changeset
|
899 size_t pos; |
0ffecd4e7e1a
added dec2str() function and largest_t type, removed itoa() and ltoa()
Timo Sirainen <tss@iki.fi>
parents:
68
diff
changeset
|
900 |
0ffecd4e7e1a
added dec2str() function and largest_t type, removed itoa() and ltoa()
Timo Sirainen <tss@iki.fi>
parents:
68
diff
changeset
|
901 if (size == 0) |
0ffecd4e7e1a
added dec2str() function and largest_t type, removed itoa() and ltoa()
Timo Sirainen <tss@iki.fi>
parents:
68
diff
changeset
|
902 return; |
0ffecd4e7e1a
added dec2str() function and largest_t type, removed itoa() and ltoa()
Timo Sirainen <tss@iki.fi>
parents:
68
diff
changeset
|
903 |
0ffecd4e7e1a
added dec2str() function and largest_t type, removed itoa() and ltoa()
Timo Sirainen <tss@iki.fi>
parents:
68
diff
changeset
|
904 pos = dec2str_recurse(buffer, 0, size, number); |
0ffecd4e7e1a
added dec2str() function and largest_t type, removed itoa() and ltoa()
Timo Sirainen <tss@iki.fi>
parents:
68
diff
changeset
|
905 |
0ffecd4e7e1a
added dec2str() function and largest_t type, removed itoa() and ltoa()
Timo Sirainen <tss@iki.fi>
parents:
68
diff
changeset
|
906 if (pos == 0 && size > 1) { |
0ffecd4e7e1a
added dec2str() function and largest_t type, removed itoa() and ltoa()
Timo Sirainen <tss@iki.fi>
parents:
68
diff
changeset
|
907 /* we wrote nothing, because number is 0 */ |
0ffecd4e7e1a
added dec2str() function and largest_t type, removed itoa() and ltoa()
Timo Sirainen <tss@iki.fi>
parents:
68
diff
changeset
|
908 buffer[0] = '0'; |
0ffecd4e7e1a
added dec2str() function and largest_t type, removed itoa() and ltoa()
Timo Sirainen <tss@iki.fi>
parents:
68
diff
changeset
|
909 pos++; |
0ffecd4e7e1a
added dec2str() function and largest_t type, removed itoa() and ltoa()
Timo Sirainen <tss@iki.fi>
parents:
68
diff
changeset
|
910 } |
0ffecd4e7e1a
added dec2str() function and largest_t type, removed itoa() and ltoa()
Timo Sirainen <tss@iki.fi>
parents:
68
diff
changeset
|
911 |
0ffecd4e7e1a
added dec2str() function and largest_t type, removed itoa() and ltoa()
Timo Sirainen <tss@iki.fi>
parents:
68
diff
changeset
|
912 buffer[pos < size ? pos : size-1] = '\0'; |
0ffecd4e7e1a
added dec2str() function and largest_t type, removed itoa() and ltoa()
Timo Sirainen <tss@iki.fi>
parents:
68
diff
changeset
|
913 } |