Rev 6424 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
647 | andrew_pro | 1 | /* |
2 | function for format output to the string |
||
6424 | siemargl | 3 | |
4 | Siemargl update formats as http://www.cplusplus.com/reference/cstdio/printf/, no wchar though |
||
5 | http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap05.html is used too |
||
6 | %g explain https://support.microsoft.com/en-us/kb/43392 |
||
7 | |||
8 | todo: |
||
9 | -fix precision in %g |
||
6425 | siemargl | 10 | -%u printed as signed, %x, %o also is promoted to long long |
11 | // FAIL 0x0FFFF7A7E as %x - signed long promotes sign, need %llx or %Lx and type conversion |
||
6424 | siemargl | 12 | -%a |
13 | -%n nothing printed |
||
14 | -%17.18f digits maximum format |
||
6425 | siemargl | 15 | -use %C as w_char L'x' (non standard extension) |
16 | -radix point always '.', no LOCALEs |
||
647 | andrew_pro | 17 | */ |
18 | |||
6424 | siemargl | 19 | |
647 | andrew_pro | 20 | #include |
21 | #include |
||
6424 | siemargl | 22 | #include |
647 | andrew_pro | 23 | #include |
6424 | siemargl | 24 | #include |
647 | andrew_pro | 25 | |
6424 | siemargl | 26 | enum flags_t |
647 | andrew_pro | 27 | { |
6424 | siemargl | 28 | flag_unsigned = 0x02, |
29 | flag_register = 0x04, |
||
30 | flag_plus = 0x08, |
||
31 | flag_left_just = 0x10, |
||
32 | flag_lead_zeros = 0x20, |
||
33 | flag_space_plus = 0x40, |
||
34 | flag_hash_sign = 0x80, |
||
35 | flag_point = 0x100 |
||
36 | }; |
||
6425 | siemargl | 37 | int formatted_double_to_string(long double number, int format1, int format2, char *s, int flags); |
38 | int formatted_double_to_string_scientific(long double number, int format1, int format2, char *s, int flags); |
||
39 | int formatted_long_to_string(long long number, int format1, int prec, char *s, int flags); |
||
40 | int formatted_hex_to_string(unsigned long long number, int fmt1, int prec, char *s, int flags); |
||
41 | int formatted_octa_to_string(unsigned long long number, int fmt1, int prec, char *s, int flags); |
||
647 | andrew_pro | 42 | |
6425 | siemargl | 43 | |
44 | int formatted_double_special(long double number, char *s) |
||
45 | // return 0 if no special values: NAN, INF. -0.0 ignored |
||
46 | // http://steve.hollasch.net/cgindex/coding/ieeefloat.html |
||
47 | { |
||
48 | struct IEEExp { |
||
49 | unsigned manl:32; |
||
50 | unsigned manh:32; |
||
51 | unsigned exp:15; |
||
52 | unsigned sign:1; |
||
53 | } *ip = (struct IEEExp *)&number; |
||
54 | |||
55 | if (ip->exp != 0x7fff) return 0; |
||
56 | |||
57 | if (ip->manh == 0x80000000 && ip->manl == 0) // Inf |
||
58 | { |
||
59 | if(ip->sign) |
||
60 | strcpy(s, "-INF"); |
||
61 | else |
||
62 | strcpy(s, "+INF"); |
||
63 | } else |
||
64 | if (ip->manh & ~0x7fffffff) |
||
65 | strcpy(s, "QNaN"); |
||
66 | else |
||
67 | strcpy(s, "SNaN"); |
||
68 | |||
69 | return 4; |
||
70 | } |
||
71 | |||
72 | int copy_and_align(char *dest, int width, char *src, int src_len, char sign, int flags) |
||
73 | // alingn number in buffer, put sign and fills additional places |
||
74 | // flags used only flag_left_just and flag_lead_zeros |
||
75 | // sign can be zero, 0, x, X, space, +, - |
||
76 | { |
||
77 | int rc = 0, sign_len; |
||
78 | char fill; |
||
79 | |||
80 | fill = (flags & flag_lead_zeros) ? '0' : ' '; |
||
81 | if(sign == 'x' || sign == 'X') |
||
82 | { |
||
83 | sign_len = 2; |
||
84 | } else |
||
85 | if (sign) |
||
86 | sign_len = 1; |
||
87 | else |
||
88 | sign_len = 0; |
||
89 | |||
90 | if ((flags & flag_left_just) || (src_len + sign_len >= width)) // left justify or no room |
||
91 | { |
||
92 | if (sign) |
||
93 | { |
||
94 | if(sign == 'x' || sign == 'X') |
||
95 | { |
||
96 | dest[0] = '0'; |
||
97 | dest[1] = sign; |
||
98 | memcpy(dest + 2, src, src_len); |
||
99 | rc = src_len + 2; |
||
100 | } else |
||
101 | { // single sign |
||
102 | dest[0] = sign; |
||
103 | memcpy(dest + 1, src, src_len); |
||
104 | rc = src_len + 1; |
||
105 | } |
||
106 | } else |
||
107 | { |
||
108 | memcpy(dest, src, src_len); |
||
109 | rc = src_len; |
||
110 | } |
||
111 | if (rc < width) |
||
112 | { |
||
113 | memset(dest + rc, fill, width - rc); |
||
114 | rc = width; |
||
115 | } |
||
116 | } else // right justify and fill |
||
117 | { |
||
118 | rc = width; |
||
119 | memcpy(dest + width - src_len, src, src_len); |
||
120 | memset(dest, fill, width - src_len); |
||
121 | if (flags & flag_lead_zeros) |
||
122 | { |
||
123 | if(sign == 'x' || sign == 'X') |
||
124 | { |
||
125 | dest[0] = '0'; |
||
126 | dest[1] = sign; |
||
127 | } else |
||
128 | if (sign) dest[0] = sign; |
||
129 | } else |
||
130 | { |
||
131 | if(sign == 'x' || sign == 'X') |
||
132 | { |
||
133 | dest[width - src_len - 2] = '0'; |
||
134 | dest[width - src_len - 1] = sign; |
||
135 | } else |
||
136 | if (sign) dest[width - src_len - 1] = sign; |
||
137 | } |
||
138 | } |
||
139 | return rc; |
||
140 | } |
||
141 | |||
6424 | siemargl | 142 | int formatted_double_to_string_scientific(long double number, int format1, int format2, char *s, int flags) |
143 | { |
||
6425 | siemargl | 144 | long double norm_digit; |
145 | long mul = 0; |
||
146 | char sign = 0; |
||
147 | char buf[50]; |
||
148 | int len; |
||
149 | |||
150 | if((flags & flag_point) == 0) format2 = 6; // default prec if no point spec |
||
151 | |||
152 | len = formatted_double_special(number, buf); |
||
153 | if (len == 0) |
||
154 | { |
||
155 | if (number < 0) { sign = '-'; norm_digit = -number; } |
||
156 | else |
||
157 | { |
||
158 | norm_digit = number; |
||
159 | if (flags & flag_plus) sign = '+'; else |
||
160 | if (flags & flag_space_plus) sign = ' '; |
||
161 | } |
||
162 | // normalize |
||
163 | while (norm_digit < 1.0) { norm_digit *= 10; mul--; } |
||
164 | while (norm_digit >= 10.0) { norm_digit /= 10; mul++; } |
||
165 | |||
166 | len = formatted_double_to_string(norm_digit, 0, format2, buf, flags & ~(flag_plus | flag_space_plus)); |
||
167 | |||
168 | if (flags & flag_register) |
||
169 | buf[len++] = 'E'; |
||
170 | else |
||
171 | buf[len++] = 'e'; |
||
172 | |||
173 | len += formatted_long_to_string(mul, 0, 3, buf + len, flag_plus | flag_lead_zeros); |
||
174 | } |
||
175 | else |
||
176 | flags &= ~flag_lead_zeros; // no need for INF, NAN |
||
177 | |||
178 | len = copy_and_align(s, format1, buf, len, sign, flags); |
||
179 | |||
180 | return len; |
||
6424 | siemargl | 181 | } |
647 | andrew_pro | 182 | |
6424 | siemargl | 183 | int formatted_double_to_string(long double number, int format1, int format2, char *s, int flags) |
184 | { |
||
6425 | siemargl | 185 | long double nafter, beforpointdigit; |
186 | long long intdigit, mul; |
||
187 | int div; |
||
188 | int i; |
||
189 | char sign = 0; |
||
190 | int fmt1; |
||
191 | int fmt2; |
||
192 | char buf[100], *pbuf = buf; |
||
193 | char buf_low[50], *pbuf_lo = buf_low; |
||
647 | andrew_pro | 194 | |
6425 | siemargl | 195 | if((flags & flag_point) == 0) format2 = 6; // default prec if no point spec |
647 | andrew_pro | 196 | |
6425 | siemargl | 197 | i = formatted_double_special(number, buf); |
198 | if (i == 0) |
||
199 | { |
||
200 | if (number < 0) {sign = '-'; number = -number; } |
||
6424 | siemargl | 201 | else |
202 | { |
||
6425 | siemargl | 203 | if (flags & flag_plus) sign = '+'; else |
204 | if (flags & flag_space_plus) sign = ' '; |
||
6424 | siemargl | 205 | } |
647 | andrew_pro | 206 | |
6424 | siemargl | 207 | fmt1 = 1; |
208 | fmt2 = format2; |
||
209 | if (fmt2 > 18) fmt2 = 18; //maximum size of long long type |
||
647 | andrew_pro | 210 | |
6424 | siemargl | 211 | beforpointdigit = floor(number + 0.00000000000001); |
212 | nafter = number - beforpointdigit; |
||
213 | |||
214 | //print part of number before point |
||
215 | mul = 1; |
||
216 | for(i = 0; i < sizeof buf - 1; i++) |
||
217 | { |
||
218 | mul *= 10; |
||
219 | if ((beforpointdigit/mul) < 1.0) { fmt1 = i + 1; break; } |
||
647 | andrew_pro | 220 | } |
6424 | siemargl | 221 | if (i == sizeof buf - 1 || fmt1 > 17) |
222 | { |
||
223 | strcpy(s, "[too big number for %f, %a]"); |
||
224 | return strlen(s); |
||
225 | } |
||
647 | andrew_pro | 226 | |
6424 | siemargl | 227 | mul /= 10; |
228 | while(mul > 1) |
||
229 | { |
||
230 | div = beforpointdigit / mul; |
||
231 | *pbuf++ = (char)div + '0'; |
||
232 | beforpointdigit = beforpointdigit - div * mul; |
||
233 | mul /= 10; |
||
234 | } |
||
235 | *pbuf++=(char)beforpointdigit + '0'; |
||
647 | andrew_pro | 236 | |
6424 | siemargl | 237 | //print part of number after point |
238 | mul = 1; |
||
239 | for(i = 0; i < fmt2; i++) |
||
240 | { |
||
241 | nafter = nafter*10; |
||
242 | mul *= 10; |
||
243 | } |
||
647 | andrew_pro | 244 | |
6424 | siemargl | 245 | intdigit = roundl(nafter); |
647 | andrew_pro | 246 | |
6424 | siemargl | 247 | mul /= 10; |
248 | for(i = 0; i < fmt2 - 1; i++) |
||
249 | { |
||
250 | div = intdigit / mul; |
||
251 | *pbuf_lo++=(char)div + '0'; |
||
252 | intdigit = intdigit - div * mul; |
||
253 | mul /= 10; |
||
254 | if (mul == 1) break; |
||
255 | } |
||
256 | *pbuf_lo++ = (char)intdigit + '0'; |
||
647 | andrew_pro | 257 | |
6425 | siemargl | 258 | // form full number |
6424 | siemargl | 259 | if (roundl(nafter) != 0 || fmt2 != 0) |
260 | { |
||
6425 | siemargl | 261 | *pbuf++ = '.'; |
262 | memcpy(pbuf, buf_low, pbuf_lo - buf_low); pbuf += pbuf_lo - buf_low; |
||
6424 | siemargl | 263 | } else if (flags & flag_hash_sign) |
6425 | siemargl | 264 | *pbuf++ = '.'; |
265 | } |
||
266 | else |
||
267 | { |
||
268 | flags &= ~flag_lead_zeros; // no need for INF, NAN |
||
269 | pbuf += i; |
||
270 | } |
||
647 | andrew_pro | 271 | |
6425 | siemargl | 272 | return copy_and_align(s, format1, buf, pbuf - buf, sign, flags); |
647 | andrew_pro | 273 | } |
274 | |||
6424 | siemargl | 275 | int formatted_long_to_string(long long number, int format1, int prec, char *s, int flags) |
647 | andrew_pro | 276 | { |
6424 | siemargl | 277 | int i; |
278 | int fmt; |
||
6425 | siemargl | 279 | char sign = 0; |
6424 | siemargl | 280 | long long digit; |
281 | long long mul; |
||
282 | int div; |
||
283 | char buf[100], *pbuf = buf; |
||
647 | andrew_pro | 284 | |
6424 | siemargl | 285 | if (number == -9223372036854775807LL - 1) // overflow all our math, cant minus this |
286 | { |
||
6425 | siemargl | 287 | strcpy(s, "-9223372036854775808"); |
288 | return strlen(s); |
||
6424 | siemargl | 289 | } |
647 | andrew_pro | 290 | |
6424 | siemargl | 291 | if (flags & flag_point) flags &= ~flag_lead_zeros; // conflicting flags |
647 | andrew_pro | 292 | |
6425 | siemargl | 293 | if (number < 0) {sign = '-'; number = -number; } |
6424 | siemargl | 294 | else |
295 | { |
||
6425 | siemargl | 296 | if (flags & flag_plus) sign = '+'; else |
297 | if (flags & flag_space_plus) sign = ' '; |
||
6424 | siemargl | 298 | } |
647 | andrew_pro | 299 | |
6424 | siemargl | 300 | digit = number; |
647 | andrew_pro | 301 | |
6424 | siemargl | 302 | mul = (digit < 0) ? -1 : 1; |
647 | andrew_pro | 303 | |
6424 | siemargl | 304 | for(i = 0; i < sizeof buf - 2; i++) |
305 | { |
||
306 | if (digit / mul < 10) { fmt = i + 1; break; } |
||
307 | mul *= 10; |
||
308 | } |
||
309 | |||
6425 | siemargl | 310 | // add leading zeros by prec |
6424 | siemargl | 311 | for(i = 0; i < prec - fmt; i++) *pbuf++ = '0'; |
312 | |||
313 | for(i = 0; i < fmt - 1; i++) |
||
314 | { |
||
315 | div = digit / mul; |
||
316 | *pbuf++ = (char)div + '0'; |
||
317 | digit = digit - div * mul; |
||
318 | mul /= 10; |
||
319 | if (mul == 1 || mul == -1) break; |
||
320 | } |
||
321 | *pbuf++ = (char)digit + '0'; |
||
322 | |||
6425 | siemargl | 323 | return copy_and_align(s, format1, buf, pbuf - buf, sign, flags); |
647 | andrew_pro | 324 | } |
325 | |||
6425 | siemargl | 326 | int formatted_hex_to_string(unsigned long long number, int fmt1, int prec, char *s, int flags) |
647 | andrew_pro | 327 | { |
6425 | siemargl | 328 | unsigned long long digit, mul; |
329 | int i, div, fmt; |
||
330 | char xdigs_lower[16]="0123456789abcdef"; |
||
331 | char xdigs_upper[16]="0123456789ABCDEF"; |
||
332 | char buf[50], *pbuf = buf, sign; |
||
647 | andrew_pro | 333 | |
6425 | siemargl | 334 | if (number == -9223372036854775807LL - 1) // overflow all our math, cant minus this |
335 | { |
||
336 | strcpy(buf, "FFFFFFFFFFFFFFFF"); |
||
337 | pbuf += strlen(buf); |
||
338 | } |
||
339 | else |
||
340 | { |
||
341 | if (flags & flag_point) flags &= ~flag_lead_zeros; // conflicting flags |
||
647 | andrew_pro | 342 | |
6425 | siemargl | 343 | digit = number; |
647 | andrew_pro | 344 | |
6425 | siemargl | 345 | mul = (digit < 0) ? -1 : 1; |
346 | |||
347 | for(i = 0; i < sizeof buf - 2; i++) |
||
647 | andrew_pro | 348 | { |
6425 | siemargl | 349 | if (digit / mul < 16) { fmt = i + 1; break; } |
350 | mul <<= 4; |
||
647 | andrew_pro | 351 | } |
352 | |||
6425 | siemargl | 353 | // add leading zeros by prec |
354 | for(i = 0; i < prec - fmt; i++) *pbuf++ = '0'; |
||
647 | andrew_pro | 355 | |
6425 | siemargl | 356 | for(i = 0; i < fmt - 1; i++) |
647 | andrew_pro | 357 | { |
6425 | siemargl | 358 | div = digit / mul; |
359 | *pbuf++ = (flags & flag_register) ? xdigs_upper[div] : xdigs_lower[div]; |
||
360 | digit = digit - div * mul; |
||
361 | mul >>= 4; |
||
362 | if (mul == 1 || mul == -1) break; |
||
647 | andrew_pro | 363 | } |
6425 | siemargl | 364 | *pbuf++ = (flags & flag_register) ? xdigs_upper[digit] : xdigs_lower[digit]; |
365 | } |
||
647 | andrew_pro | 366 | |
6425 | siemargl | 367 | sign = 0; |
368 | if(flags & flag_hash_sign) |
||
369 | sign = (flags & flag_register) ? 'X' : 'x'; |
||
370 | |||
371 | return copy_and_align(s, fmt1, buf, pbuf - buf, sign, flags); |
||
647 | andrew_pro | 372 | } |
373 | |||
6425 | siemargl | 374 | int formatted_octa_to_string(unsigned long long number, int fmt1, int prec, char *s, int flags) |
647 | andrew_pro | 375 | { |
6425 | siemargl | 376 | unsigned long long digit, mul; |
377 | int i, div, fmt; |
||
378 | char xdigs_lower[16]="01234567"; |
||
379 | char buf[50], *pbuf = buf; |
||
647 | andrew_pro | 380 | |
6425 | siemargl | 381 | if (number == -9223372036854775807LL - 1) // overflow all our math, cant minus this |
382 | { |
||
383 | strcpy(buf, "1777777777777777777777"); |
||
384 | pbuf += strlen(buf); |
||
385 | } |
||
386 | else |
||
387 | { |
||
388 | if (flags & flag_point) flags &= ~flag_lead_zeros; // conflicting flags |
||
647 | andrew_pro | 389 | |
6425 | siemargl | 390 | digit = number; |
647 | andrew_pro | 391 | |
6425 | siemargl | 392 | mul = (digit < 0) ? -1 : 1; |
393 | |||
394 | for(i = 0; i < sizeof buf - 2; i++) |
||
647 | andrew_pro | 395 | { |
6425 | siemargl | 396 | if (digit / mul < 8) { fmt = i + 1; break; } |
397 | mul <<= 3; |
||
647 | andrew_pro | 398 | } |
399 | |||
6425 | siemargl | 400 | // add leading zeros by prec |
401 | for(i = 0; i < prec - fmt; i++) *pbuf++ = '0'; |
||
647 | andrew_pro | 402 | |
6425 | siemargl | 403 | for(i = 0; i < fmt - 1; i++) |
647 | andrew_pro | 404 | { |
6425 | siemargl | 405 | div = digit / mul; |
406 | *pbuf++ = xdigs_lower[div & 0x7]; |
||
407 | digit = digit - div * mul; |
||
408 | mul >>= 3; |
||
409 | if (mul == 1 || mul == -1) break; |
||
647 | andrew_pro | 410 | } |
6425 | siemargl | 411 | *pbuf++ = xdigs_lower[digit]; |
412 | } |
||
647 | andrew_pro | 413 | |
6425 | siemargl | 414 | return copy_and_align(s, fmt1, buf, pbuf - buf, (flags & flag_hash_sign) ? '0' : 0, flags); |
647 | andrew_pro | 415 | } |
416 | |||
6424 | siemargl | 417 | //int vsnprintf (char * s, size_t n, const char * format, va_list arg ); |
418 | int format_print(char *dest, size_t maxlen, const char *fmt0, va_list argp) |
||
647 | andrew_pro | 419 | { |
6424 | siemargl | 420 | int i; |
421 | int length; |
||
422 | int fmt1, fmt2; // width, precision |
||
423 | size_t pos, posc; |
||
424 | long long intdigit; |
||
425 | long double doubledigit; |
||
426 | const char *fmt, *fmtc; // first point to %, fmtc points to specifier |
||
427 | char *s; // pointer to current dest char |
||
428 | char *str; |
||
429 | char buf[200]; // buffer for current argument value print representation |
||
430 | int format_flag; |
||
431 | int flag_long; // 2 = long double or long long int or wchar |
||
432 | int *point_to_n = NULL; |
||
433 | int flags; // parsed flags |
||
647 | andrew_pro | 434 | |
6424 | siemargl | 435 | fmt = fmt0; |
436 | s = dest; |
||
437 | pos = 0; |
||
438 | while(pos < maxlen) |
||
439 | { |
||
440 | if (*fmt != '%') // usual char |
||
647 | andrew_pro | 441 | { |
6424 | siemargl | 442 | if ('\0' == (*s++ = *fmt++)) break; |
443 | pos++; |
||
444 | continue; |
||
445 | } |
||
647 | andrew_pro | 446 | |
6424 | siemargl | 447 | if (*(fmt + 1) == '%') // %% |
448 | { |
||
449 | *s++ = '%'; pos++; |
||
450 | fmt += 2; |
||
451 | continue; |
||
452 | } |
||
453 | //checking to containg format in the string |
||
454 | fmtc = fmt; |
||
455 | posc = pos; |
||
647 | andrew_pro | 456 | |
6424 | siemargl | 457 | flags = 0; |
458 | format_flag = 0; |
||
459 | flag_long = 0; // 2 = long double or long long int or wchar |
||
647 | andrew_pro | 460 | |
6424 | siemargl | 461 | while(*fmtc != '\0' && !format_flag) // searching end of format |
462 | { |
||
463 | fmtc++; posc++; |
||
464 | switch( *fmtc ) |
||
465 | { |
||
466 | case 'a': |
||
467 | format_flag = 1; |
||
468 | flags |= flag_unsigned; |
||
469 | break; |
||
470 | case 'A': |
||
471 | format_flag = 1; |
||
472 | flags |= flag_unsigned | flag_register; |
||
473 | break; |
||
474 | case 'c': case 'd': case 'i': case 'e': case 'f': case 'g': case 's': case 'n': |
||
475 | format_flag = 1; |
||
476 | break; |
||
477 | case 'E': case 'F': case 'G': |
||
478 | format_flag = 1; |
||
479 | flags |= flag_register; |
||
480 | break; |
||
481 | case 'l': |
||
482 | flag_long = flag_long ? 2 : 1; // ll.eq.L |
||
483 | break; |
||
484 | case 'L': |
||
485 | flag_long = 2; |
||
486 | break; |
||
487 | case 'o': case 'u': case 'x': case 'p': |
||
488 | format_flag = 1; |
||
489 | flags |= flag_unsigned; |
||
490 | break; |
||
491 | case 'X': case 'P': |
||
492 | format_flag = 1; |
||
493 | flags |= flag_unsigned | flag_register; |
||
494 | break; |
||
495 | case '+': |
||
496 | flags |= flag_plus; |
||
497 | break; |
||
498 | case '-': |
||
499 | flags |= flag_left_just; |
||
500 | break; |
||
501 | case ' ': // space |
||
502 | flags |= flag_space_plus; |
||
503 | break; |
||
504 | case '#': |
||
505 | flags |= flag_hash_sign; |
||
506 | break; |
||
507 | case '*': case '.': // just skip |
||
508 | break; |
||
509 | default: |
||
510 | if(isdigit(*fmtc)) break; |
||
511 | strncpy(dest, "print format error - in % invalid char found", maxlen); |
||
512 | return -1; // non format char found - user error |
||
513 | } |
||
514 | } |
||
647 | andrew_pro | 515 | |
6424 | siemargl | 516 | if (format_flag == 0) |
517 | { |
||
518 | strncpy(dest, "print format error - % without format specifier", maxlen); |
||
519 | return -1; // format char not found - user error |
||
520 | } |
||
647 | andrew_pro | 521 | |
6424 | siemargl | 522 | fmt1 = 0; |
523 | fmt2 = 0; |
||
524 | if (posc - pos > 1) // try to read width, precision |
||
525 | { |
||
526 | fmt++; |
||
527 | for(i = pos + 1; i < posc; i++) |
||
528 | { |
||
529 | switch(*fmt) |
||
530 | { |
||
531 | case '0': |
||
532 | if(fmt1 == 0 && (flags & flag_point) == 0) flags |= flag_lead_zeros; |
||
533 | case '1': case '2': case '3': case '4': |
||
534 | case '5': case '6': case '7': case '8': case '9': |
||
535 | if ((flags & flag_point) == 0) |
||
536 | fmt1 = fmt1 * 10 + (*fmt -'0'); |
||
537 | else |
||
538 | fmt2 = fmt2 * 10 + (*fmt -'0'); |
||
539 | break; |
||
540 | case '*': |
||
541 | if (flag_point == 0) |
||
542 | fmt1 = va_arg(argp, int); |
||
543 | else |
||
544 | fmt2 = va_arg(argp, int); |
||
545 | break; |
||
546 | case '.': |
||
547 | flags |= flag_point; |
||
548 | break; |
||
549 | case 'l': case 'L': case '+': // valid chars - skip |
||
550 | case '-': case ' ': case '#': |
||
551 | break; |
||
552 | default: // must be error |
||
553 | strncpy(dest, "print format error - %width.precision", maxlen); |
||
554 | return -1; // format char not found - user error |
||
555 | } |
||
556 | fmt++; |
||
557 | } |
||
558 | } |
||
647 | andrew_pro | 559 | |
6424 | siemargl | 560 | // do real work - format arguments values |
561 | length = 0; |
||
562 | switch(*fmtc) |
||
563 | { |
||
564 | case 'n': |
||
565 | point_to_n = va_arg(argp, int*); |
||
566 | break; |
||
567 | case 'c': |
||
568 | if (pos + 1 <= maxlen) |
||
569 | { |
||
570 | buf[0] = (char)va_arg(argp, int); |
||
571 | length = 1; |
||
572 | } |
||
573 | break; |
||
574 | case 's': // special case - without buf |
||
575 | str = va_arg(argp, char*); |
||
576 | length = strlen(str); |
||
577 | if ((flags & flag_point) && (length > fmt2)) length = fmt2; // cut by precision |
||
578 | if (pos + length > maxlen) length = maxlen - pos; |
||
579 | memcpy(s, str ,length); |
||
580 | s += length; |
||
581 | pos += length; |
||
582 | break; |
||
583 | case 'd': case 'i': case 'u': case 'U': |
||
584 | if (flag_long == 0) intdigit = va_arg(argp, int); else |
||
585 | if (flag_long == 1) intdigit = va_arg(argp, long); else |
||
586 | if (flag_long == 2) intdigit = va_arg(argp, long long); |
||
587 | length = formatted_long_to_string(intdigit, fmt1, fmt2, buf, flags); |
||
588 | break; |
||
589 | case 'o': |
||
590 | if (flag_long == 0) intdigit = va_arg(argp, int); else |
||
591 | if (flag_long == 1) intdigit = va_arg(argp, long); else |
||
592 | if (flag_long == 2) intdigit = va_arg(argp, long long); |
||
6425 | siemargl | 593 | length = formatted_octa_to_string(intdigit, fmt1, fmt2, buf, flags); |
6424 | siemargl | 594 | break; |
595 | case 'p': case 'P': case 'x': case 'X': |
||
596 | if (flag_long == 0) intdigit = va_arg(argp, int); else |
||
597 | if (flag_long == 1) intdigit = va_arg(argp, long); else |
||
598 | if (flag_long == 2) intdigit = va_arg(argp, long long); |
||
6425 | siemargl | 599 | length=formatted_hex_to_string(intdigit, fmt1, fmt2, buf, flags); |
6424 | siemargl | 600 | break; |
601 | case 'a': case 'A': case 'f': case 'F': |
||
602 | if (flag_long <= 1) doubledigit = va_arg(argp, double); else |
||
603 | if (flag_long == 2) doubledigit = va_arg(argp, long double); |
||
604 | length = formatted_double_to_string(doubledigit, fmt1, fmt2, buf, flags); |
||
605 | break; |
||
606 | case 'e': case 'E': |
||
607 | if (flag_long <= 1) doubledigit = va_arg(argp, double); else |
||
608 | if (flag_long == 2) doubledigit = va_arg(argp, long double); |
||
609 | length = formatted_double_to_string_scientific(doubledigit, fmt1, fmt2, buf, flags); |
||
610 | break; |
||
611 | case 'g': case 'G': |
||
612 | //prec special case, this is just workaround |
||
613 | if (flag_long <= 1) doubledigit = va_arg(argp, double); else |
||
614 | if (flag_long == 2) doubledigit = va_arg(argp, long double); |
||
615 | length = formatted_double_to_string(doubledigit, fmt1, fmt2, buf, flags); |
||
616 | i = formatted_double_to_string_scientific(doubledigit, fmt1, fmt2, buf + sizeof buf / 2, flags); |
||
617 | if(length > i) |
||
618 | { |
||
619 | memcpy(buf, buf + sizeof buf / 2, i); |
||
620 | length = i; |
||
621 | } |
||
622 | break; |
||
623 | } |
||
624 | if (*fmtc != 's' && length > 0) // skip multiple string copying |
||
625 | { |
||
626 | if (pos + length > maxlen) length = maxlen - pos; |
||
627 | memcpy(s, buf, length); |
||
628 | s += length; |
||
629 | pos += length; |
||
630 | } |
||
631 | fmt = fmtc + 1; |
||
632 | } |
||
647 | andrew_pro | 633 | |
6424 | siemargl | 634 | if (point_to_n) *point_to_n = pos; |
635 | return(pos); |
||
647 | andrew_pro | 636 | }=>=>=>=>>>>>=><=>>>>>>=><=>>>>>>>>>>>>>>>>>> |