Ticket #272: _output.c

File _output.c, 38.6 KB (added by dmik, 11 years ago)
Line 
1/* _output.c (emx+gcc) -- Copyright (c) 1990-2000 by Eberhard Mattes */
2/* wide char changes by Dmitriy Kuminov */
3
4#ifdef WIDECHAR
5#define CHAR_T wchar_t
6#define CHAR_L(str) L##str
7#define NAME(id) id##_wchar
8#define CMEMSET wmemset
9#define CMEMMOVE wmemmove
10#define CSTRLEN wcslen
11#define CTOUPPER towupper
12#define ULTOSTR uint32_to_wstr
13#define ULLTOSTR uint64_to_wstr
14#define REMOVE_ZEROES wremove_zeros
15#define DTOSTR legacy_dtowstr
16#else
17#define CHAR_T char
18#define CHAR_L(str) str
19#define NAME(id) id
20#define CMEMSET memset
21#define CMEMMOVE memmove
22#define CSTRLEN strlen
23#define CTOUPPER toupper
24#define ULTOSTR _ultoa
25#define ULLTOSTR _ulltoa
26#define REMOVE_ZEROES __remove_zeros
27#define DTOSTR __legacy_dtoa
28#endif
29
30#define SIZEOF_ARRAY(a) (sizeof (a)/ sizeof ((a)[0]))
31
32#ifndef STANDALONE
33#include "libc-alias.h"
34#else
35#include <errno.h>
36#include <sys/fmutex.h>
37#endif
38#include <stdio.h>
39#include <stdlib.h>
40#include <stdarg.h>
41#include <stdint.h>
42#include <string.h>
43#include <math.h>
44#include <float.h>
45#include <limits.h>
46#include <locale.h>
47#include <emx/io.h>
48#include <emx/float.h>
49#include <InnoTekLIBC/locale.h>
50#include <wchar.h>
51#ifdef WIDECHAR
52#include <wctype.h>
53#else
54#include <ctype.h>
55#endif
56#ifndef STANDALONE
57#include "getputc.h"
58#else
59static inline int _putc_inline (int _c, FILE *_s)
60{
61 return (--_s->_wcount >= 0 && (_c != '\n' || !(_s->_flags & _IOLBF))
62 ? (unsigned char)(*_s->_ptr++ = (char)_c)
63 : _flush (_c, _s));
64}
65#endif
66
67#ifdef WIDECHAR
68static inline int NAME(_putc_inline) (CHAR_T _c, FILE *_s)
69{
70 return ((_s->_wcount -= sizeof(CHAR_T)) >= 0 && (_c != '\n' || !(_s->_flags & _IOLBF))
71 ? (*((CHAR_T *)(_s->_ptr)) = (CHAR_T)_c, _s->_ptr += sizeof(CHAR_T), _c)
72 // Note: the above will not work when sizeof(CHAR_T) > 2 but currenlty we don't care
73 : (_flush (_c, _s), _flush (_c >> 8, _s), _c));
74}
75#endif
76
77#define FALSE 0
78#define TRUE 1
79
80#define SIZE_HH (('h' << 8) | 'h')
81#define SIZE_LL (('l' << 8) | 'l')
82
83/* ASSUMES that there are no odd integer sizes (like char being 7 bit or similar weirdnesses). */
84
85#define IS_SIZE_64BIT(size) ( (sizeof(long long) == sizeof(uint64_t) && ((size) == 'L' || (size) == SIZE_LL || (size) == 'q')) \
86 || (sizeof(size_t) == sizeof(uint64_t) && ((size) == 'z' || (size) == 'z')) \
87 || (sizeof(uintmax_t) == sizeof(uint64_t) && (size) == 'j') \
88 || (sizeof(ptrdiff_t) == sizeof(uint64_t) && (size) == 't') \
89 || (sizeof(int) == sizeof(uint64_t) && (size) == 0) \
90 || (sizeof(short) == sizeof(uint64_t) && (size) == 'h') \
91 || (sizeof(char) == sizeof(uint64_t) && (size) == SIZE_HH) \
92 )
93
94#define IS_SIZE_32BIT(size) ( (sizeof(long long) == sizeof(uint32_t) && ((size) == 'L' || (size) == SIZE_LL || (size) == 'q')) \
95 || (sizeof(size_t) == sizeof(uint32_t) && ((size) == 'z' || (size) == 'z')) \
96 || (sizeof(uintmax_t) == sizeof(uint32_t) && (size) == 'j') \
97 || (sizeof(ptrdiff_t) == sizeof(uint32_t) && (size) == 't') \
98 || (sizeof(int) == sizeof(uint32_t) && (size) == 0) \
99 || (sizeof(short) == sizeof(uint32_t) && (size) == 'h') \
100 || (sizeof(char) == sizeof(uint32_t) && (size) == SIZE_HH) \
101 )
102
103#define IS_SIZE_LE_32BIT(size) ( (sizeof(long long) <= sizeof(uint32_t) && ((size) == 'L' || (size) == SIZE_LL || (size) == 'q')) \
104 || (sizeof(size_t) <= sizeof(uint32_t) && ((size) == 'z' || (size) == 'z')) \
105 || (sizeof(uintmax_t) <= sizeof(uint32_t) && (size) == 'j') \
106 || (sizeof(ptrdiff_t) <= sizeof(uint32_t) && (size) == 't') \
107 || (sizeof(int) <= sizeof(uint32_t) && (size) == 0) \
108 || (sizeof(short) <= sizeof(uint32_t) && (size) == 'h') \
109 || (sizeof(char) <= sizeof(uint32_t) && (size) == SIZE_HH) \
110 )
111
112#define IS_SIZE_16BIT(size) ( (sizeof(long long) == sizeof(uint16_t) && ((size) == 'L' || (size) == SIZE_LL || (size) == 'q')) \
113 || (sizeof(size_t) == sizeof(uint16_t) && ((size) == 'z' || (size) == 'z')) \
114 || (sizeof(uintmax_t) == sizeof(uint16_t) && (size) == 'j') \
115 || (sizeof(ptrdiff_t) == sizeof(uint16_t) && (size) == 't') \
116 || (sizeof(int) == sizeof(uint16_t) && (size) == 0) \
117 || (sizeof(short) == sizeof(uint16_t) && (size) == 'h') \
118 || (sizeof(char) == sizeof(uint16_t) && (size) == SIZE_HH) \
119 )
120
121#define IS_SIZE_8BIT(size) ( (sizeof(long long) == sizeof(uint8_t) && ((size) == 'L' || (size) == SIZE_LL || (size) == 'q')) \
122 || (sizeof(size_t) == sizeof(uint8_t) && ((size) == 'z' || (size) == 'z')) \
123 || (sizeof(uintmax_t) == sizeof(uint8_t) && (size) == 'j') \
124 || (sizeof(ptrdiff_t) == sizeof(uint8_t) && (size) == 't') \
125 || (sizeof(int) == sizeof(uint8_t) && (size) == 0) \
126 || (sizeof(short) == sizeof(uint8_t) && (size) == 'h') \
127 || (sizeof(char) == sizeof(uint8_t) && (size) == SIZE_HH) \
128 )
129
130
131#define DEFAULT_PREC 6
132
133#define BEGIN do {
134#define END } while (0)
135
136/* All functions in this module return -1 if an error ocurred while
137 writing the target file. Otherwise, _output() returns the number
138 of characters written, all other functions return 0.
139
140 The CHECK macro is used to return -1 if the expression X evaluates
141 to a non-zero value. This is used to pass up errors. */
142
143#define CHECK(X) BEGIN \
144 if ((X) != 0) \
145 return -1; \
146 END
147
148/* Write the character C. Note the return statement! */
149
150#define PUTC(V,C) BEGIN \
151 if (NAME(_putc_inline) (C, (V)->stream) == EOF) \
152 return -1; \
153 ++(V)->count; \
154 END
155
156#define SAFE_STRLEN(S) (((S) == NULL) ? 0 : CSTRLEN (S))
157
158/* This structure holds the local variables of _output() which are
159 passed to the various functions called by _output(). */
160
161typedef struct
162{
163 FILE *stream; /* Where output should go */
164 char minus; /* Non-zero if `-' flag present */
165 char plus; /* Non-zero if `+' flag present */
166 char blank; /* Non-zero if ` ' flag present */
167 char hash; /* Non-zero if `#' flag present */
168 char pad; /* Pad character (' ' or '0') */
169 int width; /* Field width (or 0 if none specified) */
170 int prec; /* Precision (or -1 if none specified) */
171 int count; /* Number of characters printed */
172 int dig; /* DBL_DIG / LDBL_DIG for __small_dtoa() */
173} olocal;
174
175static CHAR_T zdot[] = CHAR_L ("0."); /* "0." for the current locale */
176
177
178static CHAR_T *str_upper (CHAR_T *s)
179{
180 CHAR_T *p = s;
181 while (*p = CTOUPPER (*p)) ++p;
182 return s;
183}
184
185
186#ifdef WIDECHAR
187static void uint32_to_wstr(uint32_t n, CHAR_T *buf, int radix)
188{
189 // assume buf only cotains ASCII numbers
190 char *ptr = (char *) buf;
191 _ultoa (n, ptr, radix);
192 int len = strlen (ptr);
193 CHAR_T *wptr = buf + len;
194 ptr += len;
195 while (ptr >= (char *) buf)
196 *wptr-- = (CHAR_T) *ptr--;
197}
198
199static void uint64_to_wstr(uint64_t n, CHAR_T *buf, int radix)
200{
201 // assume buf only cotains ASCII numbers
202 char *ptr = (char *) buf;
203 _ulltoa (n, ptr, radix);
204 int len = strlen (ptr);
205 CHAR_T *wptr = buf + len;
206 ptr += len;
207 while (ptr >= (char *) buf)
208 *wptr-- = (CHAR_T) *ptr--;
209}
210
211
212static void wremove_zeros (CHAR_T *digits, int keep)
213{
214 int i;
215 i = CSTRLEN (digits) - 1;
216 while (i >= keep && digits[i] == '0')
217 --i;
218 digits[i+1] = 0;
219}
220
221
222static CHAR_T *legacy_dtowstr (CHAR_T *buffer, int *p_exp, long double x, int ndigits,
223 int fmt, int dig)
224{
225 // assume buf only cotains ASCII numbers
226 char *ptr = (char *) buffer;
227 char *result = __legacy_dtoa (ptr, p_exp, x, ndigits, fmt, dig);
228 int len = strlen (ptr);
229 CHAR_T *wptr = buffer + len;
230 ptr += len;
231 while (ptr >= result)
232 *wptr-- = (CHAR_T) *ptr--;
233 return ++wptr;
234}
235#endif /* WIDECHAR */
236
237
238/* Print the first N characters of the string S. */
239
240static int out_str (olocal *v, const CHAR_T *s, int n)
241{
242 if (n >= 16)
243 {
244 if (fwrite_unlocked (s, sizeof(CHAR_T), n, v->stream) != n * sizeof(CHAR_T))
245 return -1;
246 v->count += n;
247 }
248 else
249 while (n > 0)
250 {
251 PUTC (v, *s);
252 ++s; --n;
253 }
254 return 0;
255}
256
257
258/* Note the return statement! */
259
260#define OUT_STR(V,S,N) BEGIN if (out_str (V, S, N) != 0) return -1; END
261
262
263/* Print the character C N times. */
264
265static int out_pad (olocal *v, CHAR_T c, int n)
266{
267 CHAR_T buf[256];
268
269 if (n > SIZEOF_ARRAY (buf))
270 {
271 int i;
272
273 /* Very big padding -- do 256 characters at a time. */
274 CMEMSET (buf, c, SIZEOF_ARRAY (buf));
275 while (n > 0)
276 {
277 i = SIZEOF_ARRAY (buf);
278 if (i > n)
279 i = n;
280 OUT_STR (v, buf, i);
281 n -= i;
282 }
283 }
284 else if (n >= 16)
285 {
286 CMEMSET (buf, c, n);
287 OUT_STR (v, buf, n);
288 }
289 else
290 while (n > 0)
291 {
292 PUTC (v, c);
293 --n;
294 }
295 return 0;
296}
297
298
299/* Note the return statement! */
300
301#define OUT_PAD(V,C,N) BEGIN if (out_pad (V, C, N) != 0) return -1; END
302
303
304/* Perform formatting for the "%c" and "%s" formats. The meaning of
305 the '0' flag is not defined by ANSI for "%c" and "%s"; we always
306 use blanks for padding. */
307
308static int cvt_str (olocal *v, const char *str, int str_len)
309{
310 if (str == NULL)
311 {
312 /* Print "(null)" for the NULL pointer if the precision is big
313 enough or not specified. */
314
315 if (v->prec < 0 || v->prec >= 6)
316 str = "(null)";
317 else
318 str = "";
319 }
320
321 /* The precision, if specified, limits the number of characters to
322 be printed. If the precision is specified, the array pointed to
323 by STR does not need to be null-terminated. */
324
325 if (str_len == -1)
326 {
327 if (v->prec >= 0)
328 {
329 const char *end = (const char *)memchr (str, 0, v->prec);
330 if (end != NULL)
331 str_len = end - str;
332 else
333 str_len = v->prec;
334 }
335 else
336 str_len = strlen (str);
337 }
338 else if (v->prec >= 0 && v->prec < str_len)
339 str_len = v->prec;
340
341 /* Print the string, using blanks for padding. */
342
343 if (str_len < v->width && !v->minus)
344 OUT_PAD (v, ' ', v->width - str_len);
345#if WIDECHAR
346 mbstate_t state = {{0}};
347 int left = str_len;
348 while (left)
349 {
350 wchar_t wc;
351 size_t cb = mbrtowc(&wc, str, left, &state);
352 switch (cb)
353 {
354 /*
355 * Quit the loop.
356 */
357 case -2: /* incomplete character - we ASSUME this cannot happen. */
358 case -1: /* encoding error */
359 case 0: /* end of string */
360 left = 0;
361 break;
362
363 default:
364 str += cb;
365 left -= cb;
366 OUT_STR(v, &wc, 1);
367 break;
368 }
369 }
370#else
371 OUT_STR (v, str, str_len);
372#endif
373 if (str_len < v->width && v->minus)
374 OUT_PAD (v, ' ', v->width - str_len);
375 return 0;
376}
377
378
379/* Perform formatting for the "%C" and "%S" formats. The meaning of
380 the '0' flag is not defined by ANSI for "%C" and "%S"; we always
381 use blanks for padding. */
382
383static int cvt_wstr (olocal *v, const wchar_t *str, int str_len)
384{
385 if (str == NULL)
386 {
387 /* Print "(null)" for the NULL pointer if the precision is big
388 enough or not specified. */
389
390 if (v->prec < 0 || v->prec >= 6)
391 str = L"(null)";
392 else
393 str = L"";
394 }
395
396 /* The precision, if specified, limits the number of characters to
397 be printed. If the precision is specified, the array pointed to
398 by STR does not need to be null-terminated. */
399
400 if (str_len == -1)
401 {
402 if (v->prec >= 0)
403 {
404 const wchar_t *end = (const wchar_t *)wmemchr (str, 0, v->prec);
405 if (end != NULL)
406 str_len = end - str;
407 else
408 str_len = v->prec;
409 }
410 else
411 str_len = wcslen (str);
412 }
413 else if (v->prec >= 0 && v->prec < str_len)
414 str_len = v->prec;
415
416 /* Print the string, using blanks for padding. */
417
418 if (str_len < v->width && !v->minus)
419 OUT_PAD (v, ' ', v->width - str_len);
420#ifdef WIDECHAR
421 OUT_STR (v, str, str_len);
422#else
423 mbstate_t state = {{0}};
424 for (int i = 0; i < str_len; i++)
425 {
426 char mb[MB_LEN_MAX + 1];
427 size_t cb = wcrtomb(mb, *str, &state);
428 switch (cb)
429 {
430 /*
431 * Quit the loop.
432 */
433 case -2: /* incomplete character - we ASSUME this cannot happen. */
434 case -1: /* encoding error */
435 case 0: /* end of string */
436 i = str_len;
437 break;
438
439 default:
440 str++;
441 OUT_STR(v, mb, cb);
442 break;
443 }
444 }
445#endif
446 if (str_len < v->width && v->minus)
447 OUT_PAD (v, ' ', v->width - str_len);
448 return 0;
449}
450
451
452/* Print and pad a number (which has already been converted into
453 strings). PFX is "0x" or "0X" for hexadecimal numbers, or NULL.
454 DOT is "0." for floating point numbers in [0.0,1.0) unless using
455 exponential format, the significant digits for large floating point
456 numbers in the "%f" format, "0", or NULL. Insert LPAD0 zeros
457 between DOT and STR. STR is the number. Insert RPAD0 zeros
458 between STR and XPS. XPS is the exponent (unless it is NULL).
459 IS_SIGNED is non-zero when printing a signed number. IS_NEG is
460 non-zero for negative numbers (the strings don't contain a
461 sign). */
462
463static int cvt_number (olocal *v, const CHAR_T *pfx, const CHAR_T *dot,
464 const CHAR_T *str, const CHAR_T *xps,
465 int lpad0, int rpad0, int is_signed, int is_neg)
466{
467 int sign, pfx_len, dot_len, str_len, xps_len, min_len, lpad1;
468
469 if (!is_signed) /* No sign for %u, %o and %x */
470 sign = EOF;
471 else if (is_neg)
472 sign = '-';
473 else if (v->plus) /* '+' overrides ' ' */
474 sign = '+';
475 else if (v->blank)
476 sign = ' ';
477 else
478 sign = EOF;
479
480 pfx_len = SAFE_STRLEN (pfx);
481 dot_len = SAFE_STRLEN (dot);
482 str_len = CSTRLEN (str);
483 xps_len = SAFE_STRLEN (xps);
484
485 if (lpad0 < 0)
486 lpad0 = 0;
487 if (rpad0 < 0)
488 rpad0 = 0;
489 lpad1 = 0;
490
491 /* Compute the minimum length required for printing the number. */
492
493 min_len = lpad0 + pfx_len + dot_len + str_len + rpad0 + xps_len;
494 if (sign != EOF)
495 ++min_len;
496
497 /* If padding with zeros is requested, increase LPAD1 to pad the
498 number on the left with zeros. Note that the `-' flag
499 (left-justify) turns off padding with zeros. */
500
501 if (v->pad == '0' && min_len < v->width)
502 {
503 lpad1 += v->width - min_len;
504 min_len = v->width;
505 }
506
507 /* If DOT is empty, we can combine LPAD0 into LPAD1. */
508
509 if (dot_len == 0)
510 {
511 lpad1 += lpad0;
512 lpad0 = 0;
513 }
514
515 /* Pad on the left with blanks. */
516
517 if (min_len < v->width && !v->minus)
518 OUT_PAD (v, ' ', v->width - min_len);
519
520 /* Print the number. */
521
522 if (sign != EOF)
523 PUTC (v, sign);
524 OUT_STR (v, pfx, pfx_len);
525 OUT_PAD (v, '0', lpad1);
526 OUT_STR (v, dot, dot_len);
527 OUT_PAD (v, '0', lpad0);
528 OUT_STR (v, str, str_len);
529 OUT_PAD (v, '0', rpad0);
530 OUT_STR (v, xps, xps_len);
531
532 /* Pad on the right with blanks. */
533
534 if (min_len < v->width && v->minus)
535 OUT_PAD (v, ' ', v->width - min_len);
536 return 0;
537}
538
539
540/* Print and pad an integer (which has already been converted into the
541 string STR). PFX is "0x" or "0X" for hexadecimal numbers, or NULL.
542 ZERO is non-zero if the number is zero. IS_NEG is non-zero if the
543 number is negative (the string STR doesn't contain a sign). */
544
545static int cvt_integer (olocal *v, const CHAR_T *pfx, const CHAR_T *str,
546 int zero, int is_signed, int is_neg)
547{
548 int lpad0;
549
550 if (zero && v->prec == 0) /* ANSI */
551 return 0;
552
553 if (v->prec >= 0) /* Ignore `0' if `-' is given for an integer */
554 v->pad = ' ';
555
556 lpad0 = v->prec - CSTRLEN (str);
557 return cvt_number (v, pfx, NULL, str, NULL, lpad0, 0, is_signed, is_neg);
558}
559
560
561static int cvt_hex (olocal *v, CHAR_T *str, CHAR_T x, int zero)
562{
563 if (x == 'X')
564 str_upper (str);
565 return cvt_integer (v, ((!zero && v->hash) ? (x == 'X' ? CHAR_L ("0X") : CHAR_L ("0x")) : NULL),
566 str, zero, FALSE, FALSE);
567}
568
569
570static int cvt_hex_32 (olocal *v, uint32_t n, CHAR_T x)
571{
572 CHAR_T buf[9];
573
574 ULTOSTR (n, buf, 16);
575 return cvt_hex (v, buf, x, n == 0);
576}
577
578
579static int cvt_hex_64 (olocal *v, uint64_t n, CHAR_T x)
580{
581 CHAR_T buf[17];
582
583 ULLTOSTR (n, buf, 16);
584 return cvt_hex (v, buf, x, n == 0);
585}
586
587
588static int cvt_oct (olocal *v, const CHAR_T *str, int zero)
589{
590 size_t len;
591
592 if (v->hash && str[0] != '0')
593 {
594 len = CSTRLEN (str);
595 if (v->prec <= (int)len)
596 v->prec = len + 1;
597 }
598 return cvt_integer (v, NULL, str, zero && !v->hash, FALSE, FALSE);
599}
600
601
602static int cvt_oct_32 (olocal *v, uint32_t n)
603{
604 CHAR_T buf[12];
605
606 ULTOSTR (n, buf, 8);
607 return cvt_oct (v, buf, n == 0);
608}
609
610
611static int cvt_oct_64 (olocal *v, uint64_t n)
612{
613 CHAR_T buf[23];
614
615 ULLTOSTR (n, buf, 8);
616 return cvt_oct (v, buf, n == 0);
617}
618
619
620static int cvt_dec_32 (olocal *v, uint32_t n, int is_signed, int is_neg)
621{
622 CHAR_T buf[11];
623
624 ULTOSTR (n, buf, 10);
625 return cvt_integer (v, NULL, buf, n == 0, is_signed, is_neg);
626}
627
628
629static int cvt_dec_64 (olocal *v, uint64_t n, int is_signed, int is_neg)
630{
631 CHAR_T buf[21];
632
633 ULLTOSTR (n, buf, 10);
634 return cvt_integer (v, NULL, buf, n == 0, is_signed, is_neg);
635}
636
637
638/* Print a floating point number (which has been turned into the digit
639 string DIGITS and the exponent XP) for the "%f" format. If IS_NEG
640 is non-zero, the number is negative. */
641
642static int cvt_fixed_digits (olocal *v, CHAR_T *digits, int xp, int is_neg,
643 int is_auto)
644{
645 int lpad0, rpad0, len, frac;
646
647 /* We have to handle 9 cases (the examples are for DECIMAL_DIG=4):
648
649 | Fmt | Number || digits | xp | pfx |lpad0|rpad0| Output
650 ----+-----+-----------++--------+----+------+-----+-----+---------
651 (1) | .3f | 0.0001234 || "1234" | -4 | "0." | 0 | 3 | 0.000
652 (2) | .7f | 0.001234 || "1234" | -3 | "0." | 2 | 1 | 0.0012340
653 (3) | .3f | 0.001234 || "1234" | -3 | "0." | 2 | 0 | 0.001
654 (4) | .3f | 0.1234 || "1234" | -1 | "0." | 0 | 0 | 0.123
655 (5) | .3f | 1.234 || "1234" | 0 | N/A | N/A | 0 | 1.234
656 (6) | .1f | 12.34 || "1234" | 1 | N/A | N/A | 0 | 12.3
657 (7) | .3f | 123.4 || "1234" | 2 | N/A | N/A | 2 | 123.400
658 (8) | .3f | 1234.0 || "1234" | 3 | N/A | N/A | 3 | 1234.000
659 (9) | .3f | 123456.0 || "1235" | 5 |"1235"| 2 | 3 | 123500.000
660
661 */
662
663
664 if (xp < 0)
665 {
666 /* Cases (1) through (4). We print "0." followed by
667
668 MIN (-xp - 1, v->prec)
669
670 zeros and the string of digit. */
671
672 lpad0 = -xp - 1; /* This is for cases (2) through (3) */
673 if (v->prec < lpad0)
674 lpad0 = v->prec; /* This is for case (1) */
675
676 /* Compute the number of zeros to append. */
677
678 rpad0 = v->prec - (lpad0 + DECIMAL_DIG); /* This is for case (2) */
679 if (rpad0 < 0)
680 rpad0 = 0; /* This is for cases (1), (3) and (4) */
681
682 /* Truncate the string of digits according to the precision for
683 cases (1), (3) and (4). */
684
685 len = v->prec - lpad0;
686 if (len >= 0 && len < DECIMAL_DIG)
687 digits[len] = 0;
688
689 if (is_auto)
690 {
691 rpad0 = 0;
692 REMOVE_ZEROES (digits, 0);
693 if (digits[0] == 0)
694 lpad0 = 0;
695 }
696
697 return cvt_number (v, NULL, ((v->hash || digits[0] != 0 || lpad0 != 0)
698 ? zdot : CHAR_L ("0")),
699 digits, NULL, lpad0, rpad0, TRUE, is_neg);
700 }
701 else if (xp < DECIMAL_DIG)
702 {
703 /* Cases (5) through (8). */
704
705 /* Compute the number of zeros to append and truncate the string
706 of digits. */
707
708 frac = DECIMAL_DIG - xp - 1; /* Number of decimals (frac >= 0) */
709 rpad0 = v->prec - frac; /* For cases (5), (7) and (8) */
710 if (rpad0 < 0)
711 {
712 /* Case (6) */
713 digits[DECIMAL_DIG + rpad0] = 0;
714 rpad0 = 0;
715 }
716
717 if (is_auto)
718 {
719 REMOVE_ZEROES (digits, xp + 1);
720 rpad0 = 0;
721 }
722
723 /* Insert the decimal point. */
724 if (v->hash || digits[xp + 1] != 0 || rpad0 != 0)
725 {
726 CMEMMOVE (digits + xp + 2, digits + xp + 1, DECIMAL_DIG - xp);
727 digits[xp + 1] = zdot[1];
728 }
729 return cvt_number (v, NULL, NULL, digits, NULL, 0, rpad0, TRUE, is_neg);
730 }
731 else
732 {
733 /* Case (9). */
734
735 lpad0 = xp - DECIMAL_DIG + 1;
736 rpad0 = (is_auto ? 0 : v->prec);
737
738 return cvt_number (v, NULL, digits,
739 ((v->hash || rpad0 != 0) ? zdot+1 : CHAR_L ("")),
740 NULL, lpad0, rpad0, TRUE, is_neg);
741 }
742}
743
744
745/* Print a floating point number (which has been turned into the digit
746 string DIGITS and the exponent XP) for the "%e" and "%g" formats.
747 If IS_NEG is non-zero, the number is negative. XP_CHAR is 'e' or
748 'E'. If IS_AUTO is non-zero, we should omit trailing zeros for the
749 "%g" format. */
750
751static int cvt_exp_digits (olocal *v, CHAR_T *digits, int xp, int is_neg,
752 CHAR_T xp_char, int is_auto)
753{
754 int i, rpad0;
755 CHAR_T xps_buf[10];
756
757 xps_buf[0] = xp_char;
758 xps_buf[1] = '+';
759 if (xp < 0)
760 {
761 xps_buf[1] = '-';
762 xp = -xp;
763 }
764 i = 2;
765 if (xp >= 1000)
766 xps_buf[i++] = (CHAR_T)((xp / 1000) % 10) + '0';
767 if (xp >= 100)
768 xps_buf[i++] = (CHAR_T)((xp / 100) % 10) + '0';
769 xps_buf[i++] = (CHAR_T)((xp / 10) % 10) + '0';
770 xps_buf[i++] = (CHAR_T)(xp % 10) + '0';
771 xps_buf[i] = 0;
772
773 /* Insert decimal point. */
774
775 if (v->prec == 0 && !v->hash)
776 {
777 digits[1] = 0;
778 rpad0 = 0;
779 }
780 else
781 {
782 CMEMMOVE (digits + 2, digits + 1, DECIMAL_DIG);
783 digits[1] = zdot[1];
784 if (v->prec >= DECIMAL_DIG)
785 rpad0 = 1 + v->prec - DECIMAL_DIG;
786 else
787 {
788 rpad0 = 0;
789 digits[2 + v->prec] = 0;
790 }
791 if (is_auto)
792 {
793 REMOVE_ZEROES (digits, 2);
794 if (digits[2] == 0)
795 digits[1] = 0;
796 rpad0 = 0;
797 }
798 }
799 return cvt_number (v, NULL, NULL, digits, xps_buf, 0, rpad0, TRUE, is_neg);
800}
801
802
803/* Perform formatting for the "%f" format. */
804
805static int cvt_fixed (olocal *v, long double x, int is_neg)
806{
807
808 if (x == 0.0)
809 return cvt_number (v, NULL, NULL, ((v->hash || v->prec > 0) ? zdot : CHAR_L ("0")),
810 NULL, 0, v->prec, TRUE, is_neg);
811 else
812 {
813 CHAR_T digits[DECIMAL_DIG+2], *p;
814 int xp;
815
816 p = DTOSTR (digits, &xp, x, v->prec, DTOA_PRINTF_F, v->dig);
817 return cvt_fixed_digits (v, p, xp, is_neg, FALSE);
818 }
819}
820
821
822/* Perform formatting for the "%e" format. XP_CHAR is 'e' or 'E'. */
823
824static int cvt_exp (olocal *v, long double x, int is_neg, CHAR_T xp_char)
825{
826 if (x == 0.0)
827 {
828 static CHAR_T xps_buf[] = CHAR_L ("e+00");
829
830 xps_buf[0] = xp_char;
831 return cvt_number (v, NULL, NULL,
832 ((v->hash || v->prec > 0) ? zdot : CHAR_L ("0")),
833 xps_buf, 0, v->prec, TRUE, is_neg);
834 }
835 else
836 {
837 CHAR_T digits[DECIMAL_DIG+2], *p;
838 int xp;
839
840 p = DTOSTR (digits, &xp, x, v->prec, DTOA_PRINTF_E, v->dig);
841 return cvt_exp_digits (v, p, xp, is_neg, xp_char, FALSE);
842 }
843}
844
845
846/* Perform formatting for the "%g" format. XP_CHAR is 'e' or 'E'. */
847
848static int cvt_auto (olocal *v, long double x, int is_neg, CHAR_T xp_char)
849{
850 /* A precision of zero is treated as a precision of 1. Note that
851 the precision defines the number of significant digits, not the
852 number of decimals! */
853
854 if (v->prec == 0)
855 v->prec = 1;
856
857 /* 0.0 is treated specially as __legacy_dtoa() etc. cannot handle that
858 case. */
859
860 if (x == 0.0)
861 return cvt_number (v, NULL, NULL, (v->hash ? zdot : CHAR_L ("0")), NULL,
862 0, (v->hash ? v->prec - 1 : 0), TRUE, is_neg);
863 else
864 {
865 CHAR_T digits[DECIMAL_DIG+2], *p;
866 int xp;
867
868 p = DTOSTR (digits, &xp, x, v->prec, DTOA_PRINTF_G, v->dig);
869
870 /* If the exponent (of "%e" format) is less than -4 or greater
871 than or equal to the precision, use "%e" format. Otherwise,
872 use "%f" format. */
873
874 if (xp < -4 || xp >= v->prec)
875 {
876 /* Adjust the precision to indicate the number of
877 decimals. */
878
879 v->prec -= 1;
880
881 /* Treat "%#g" like "%e" (except for the precision). "%g"
882 (without `#') removes trailing zeros. */
883
884 return cvt_exp_digits (v, p, xp, is_neg, xp_char, !v->hash);
885 }
886 else
887 {
888 /* Compute the number of decimals from the exponent and the
889 precision. We must not remove trailing zeros from the
890 integer part of the number! */
891
892 v->prec -= xp + 1;
893 if (v->prec < 0)
894 v->prec = 0;
895
896 return cvt_fixed_digits (v, p, xp, is_neg, !v->hash);
897 }
898 }
899}
900
901
902/* Print the floating point number X. LIM is the number of
903 significant digits of X (depending on the type of X), FMT is the
904 format character from the format string. */
905
906static int cvt_float (olocal *v, long double x, CHAR_T fmt)
907{
908 const CHAR_T *s;
909 int is_neg, fpclass;
910
911 fpclass = fpclassify (x);
912 is_neg = signbit (x);
913 switch (fpclass)
914 {
915 case FP_NAN:
916 s = (fmt & 0x20) ? CHAR_L ("nan") : CHAR_L ("NAN");
917 is_neg = 0; /* Don't print -NAN */
918 break;
919 case FP_INFINITE:
920 s = (fmt & 0x20) ? CHAR_L ("inf") : CHAR_L ("INF");
921 break;
922 default:
923 s = NULL;
924 break;
925 }
926
927 if (s != NULL)
928 {
929 v->pad = ' ';
930 return cvt_number (v, NULL, NULL, s, NULL, 0, 0, TRUE, is_neg);
931 }
932
933 if (v->prec < 0)
934 v->prec = DEFAULT_PREC;
935
936 if (is_neg)
937 x = -x;
938
939 switch (fmt)
940 {
941 case 'f':
942 case 'F':
943 return cvt_fixed (v, x, is_neg);
944
945 case 'g':
946 return cvt_auto (v, x, is_neg, 'e');
947
948 case 'G':
949 return cvt_auto (v, x, is_neg, 'E');
950
951 case 'e':
952 return cvt_exp (v, x, is_neg, 'e');
953
954 case 'E':
955 return cvt_exp (v, x, is_neg, 'E');
956
957 default:
958 abort ();
959 }
960}
961
962
963/* This is the working horse for printf() and friends. */
964
965int NAME(_output) (FILE *stream, const CHAR_T *format, char *arg_ptr)
966{
967 olocal v;
968 int size;
969 int cont;
970 CHAR_T c;
971 int mbn, shift;
972
973 /* Initialize variables. */
974
975 v.stream = stream;
976 v.count = 0;
977#ifdef STANDALONE
978 zdot[1] = localeconv()->decimal_point[0];
979#else
980 zdot[1] = __libc_gLocaleLconv.s.decimal_point[0];
981#endif
982
983 /* ANSI X3.159-1989, 4.9.6.1: "The format shall be a multibyte
984 character sequence, beginning and ending in its initial shift
985 state." */
986
987 shift = 0;
988
989 /* Interpret the string. */
990
991 while ((c = *format) != 0)
992 if (c != '%')
993 {
994#ifdef WIDECHAR
995 PUTC (&v, c);
996 ++format;
997#else
998 /* ANSI X3.159-1989, 4.9.6.1: "... ordinary multibyte
999 charcters (not %), which are copied unchanged to the output
1000 stream..."
1001
1002 Avoid the overhead of calling mblen(). */
1003
1004 if (!CHK_MBCS_PREFIX (&__libc_GLocaleCtype, c, mbn))
1005 mbn = 1;
1006 while (mbn > 0)
1007 {
1008 PUTC (&v, *format);
1009 ++format; --mbn;
1010 }
1011#endif
1012 }
1013 else if (format[1] == '%')
1014 {
1015 /* ANSI X3.159-1989, 4.9.6.1: "The complete conversion
1016 specification shall be %%." */
1017
1018 PUTC (&v, '%');
1019 format += 2;
1020 }
1021 else
1022 {
1023 v.minus = v.plus = v.blank = v.hash = FALSE;
1024 v.width = 0; v.prec = -1; size = 0; v.pad = ' ';
1025 cont = TRUE;
1026 do
1027 {
1028 ++format;
1029 switch (*format)
1030 {
1031 case '-':
1032 v.minus = TRUE;
1033 break;
1034 case '+':
1035 v.plus = TRUE;
1036 break;
1037 case '0':
1038 v.pad = '0';
1039 break;
1040 case ' ':
1041 v.blank = TRUE;
1042 break;
1043 case '#':
1044 v.hash = TRUE;
1045 break;
1046 default:
1047 cont = FALSE;
1048 break;
1049 }
1050 } while (cont);
1051
1052 /* `-' overrides `0' */
1053
1054 if (v.minus)
1055 v.pad = ' ';
1056
1057 /* Field width */
1058
1059 if (*format == '*')
1060 {
1061 ++format;
1062 v.width = va_arg (arg_ptr, int);
1063 if (v.width < 0)
1064 {
1065 v.width = -v.width;
1066 v.minus = TRUE;
1067 }
1068 }
1069 else
1070 while (*format >= '0' && *format <= '9')
1071 {
1072 v.width = v.width * 10 + (*format - '0');
1073 ++format;
1074 }
1075
1076 /* Precision */
1077
1078 if (*format == '.')
1079 {
1080 ++format;
1081 if (*format == '*')
1082 {
1083 ++format;
1084 v.prec = va_arg (arg_ptr, int);
1085 if (v.prec < 0)
1086 v.prec = -1; /* We don't need this */
1087 }
1088 else
1089 {
1090 v.prec = 0;
1091 while (*format >= '0' && *format <= '9')
1092 {
1093 v.prec = v.prec * 10 + (*format - '0');
1094 ++format;
1095 }
1096 }
1097 }
1098
1099 /* Size */
1100
1101 if ( *format == 'h' || *format == 'l' || *format == 'L'
1102 || *format == 'j' || *format == 'z' || *format == 't'
1103 || *format == 'q' || *format == 'Z' )
1104 {
1105 size = *format++;
1106 if (size == 'l' && *format == 'l')
1107 {
1108 size = SIZE_LL; ++format;
1109 }
1110 else if (size == 'h' && *format == 'h')
1111 {
1112 size = SIZE_HH; ++format;
1113 }
1114 }
1115
1116 /* Format */
1117
1118 switch (*format)
1119 {
1120 case 0:
1121 return v.count;
1122
1123 case 'n':
1124 if (IS_SIZE_64BIT(size))
1125 {
1126 int64_t *ptr = va_arg (arg_ptr, int64_t *);
1127 *ptr = v.count;
1128 }
1129 else if (IS_SIZE_16BIT(size))
1130 {
1131 int16_t *ptr = va_arg (arg_ptr, int16_t *);
1132 *ptr = v.count;
1133 }
1134 else if (IS_SIZE_8BIT(size))
1135 {
1136 int8_t *ptr = va_arg (arg_ptr, int8_t *);
1137 *ptr = v.count;
1138 }
1139 else /* 32-bit */
1140 {
1141 int32_t *ptr = va_arg (arg_ptr, int32_t *);
1142 *ptr = v.count;
1143 }
1144 break;
1145
1146 case 'c':
1147 if (size != 'l' && size != 'L')
1148 {
1149 char c;
1150
1151 c = (char)va_arg (arg_ptr, int);
1152 v.prec = 1;
1153 CHECK (cvt_str (&v, &c, 1));
1154 break;
1155 }
1156 /* fall thru */
1157 case 'C':
1158 {
1159 wchar_t wc;
1160
1161 wc = (wchar_t)va_arg (arg_ptr, int);
1162 v.prec = 1;
1163 CHECK (cvt_wstr (&v, &wc, 1));
1164 }
1165 break;
1166
1167 case 's':
1168 if (size != 'l' && size != 'L')
1169 {
1170 CHECK (cvt_str (&v, va_arg (arg_ptr, const char *), -1));
1171 break;
1172 }
1173 /* fall thru */
1174 case 'S':
1175 CHECK (cvt_wstr (&v, va_arg (arg_ptr, const wchar_t *), -1));
1176 break;
1177
1178 case 'd':
1179 case 'i':
1180 if (IS_SIZE_64BIT(size))
1181 {
1182 int64_t n = va_arg (arg_ptr, int64_t);
1183 if (n < 0)
1184 CHECK (cvt_dec_64 (&v, -n, TRUE, TRUE));
1185 else
1186 CHECK (cvt_dec_64 (&v, n, TRUE, FALSE));
1187 }
1188 else
1189 {
1190 int32_t n = va_arg (arg_ptr, int32_t);
1191 if (size == 'h')
1192 n = (short)n;
1193 else if (size == SIZE_HH)
1194 n = (char)n;
1195 if (n < 0)
1196 CHECK (cvt_dec_32 (&v, -n, TRUE, TRUE));
1197 else
1198 CHECK (cvt_dec_32 (&v, n, TRUE, FALSE));
1199 }
1200 break;
1201
1202 case 'u':
1203 if (IS_SIZE_64BIT (size))
1204 CHECK (cvt_dec_64 (&v, va_arg (arg_ptr, uint64_t), FALSE, FALSE));
1205 else
1206 {
1207 uint32_t n = va_arg (arg_ptr, uint32_t);
1208 if (size == 'h')
1209 n = (unsigned short)n;
1210 else if (size == SIZE_HH)
1211 n = (unsigned char)n;
1212 CHECK (cvt_dec_32 (&v, n, FALSE, FALSE));
1213 }
1214 break;
1215
1216 case 'p':
1217 v.hash = TRUE;
1218 if (sizeof(uintptr_t) == sizeof(uint64_t))
1219 CHECK (cvt_hex_64 (&v, va_arg (arg_ptr, uintptr_t), 'x'));
1220 else
1221 CHECK (cvt_hex_32 (&v, va_arg (arg_ptr, uintptr_t), 'x'));
1222 break;
1223
1224 case 'x':
1225 case 'X':
1226 if (IS_SIZE_64BIT (size))
1227 CHECK (cvt_hex_64 (&v, va_arg (arg_ptr, uint64_t),
1228 *format));
1229 else
1230 {
1231 uint32_t n = va_arg (arg_ptr, uint32_t);
1232 if (size == 'h')
1233 n = (unsigned short)n;
1234 else if (size == SIZE_HH)
1235 n = (unsigned char)n;
1236 CHECK (cvt_hex_32 (&v, n, *format));
1237 }
1238 break;
1239
1240 case 'o':
1241 if (IS_SIZE_64BIT (size))
1242 CHECK (cvt_oct_64 (&v, va_arg (arg_ptr, uint64_t)));
1243 else
1244 {
1245 uint32_t n = va_arg (arg_ptr, uint32_t);
1246 if (size == 'h')
1247 n = (unsigned short)n;
1248 else if (size == SIZE_HH)
1249 n = (unsigned char)n;
1250 CHECK (cvt_oct_32 (&v, n));
1251 }
1252 break;
1253
1254 case 'g':
1255 case 'G':
1256 case 'e':
1257 case 'E':
1258 case 'f':
1259 case 'F':
1260 if (size == 'L')
1261 {
1262 long double x = va_arg (arg_ptr, long double);
1263 v.dig = LDBL_DIG;
1264 CHECK (cvt_float (&v, x, *format));
1265 }
1266 else
1267 {
1268 double x = va_arg (arg_ptr, double);
1269 v.dig = DBL_DIG;
1270 CHECK (cvt_float (&v, x, *format));
1271 }
1272 break;
1273
1274 case 'm': /* GLIBC extension which equals '%s' with strerror(errno). */
1275 CHECK (cvt_str (&v, strerror(errno), -1));
1276 break;
1277
1278 default:
1279
1280 /* ANSI X3.159-1989, 4.9.6.1: "If a conversion
1281 specification is invalid, the behavior is undefined."
1282
1283 We print the last letter only. */
1284
1285 OUT_STR (&v, format, 1);
1286 break;
1287 }
1288 ++format;
1289 }
1290
1291 /* Return the number of characters printed. */
1292
1293 return v.count;
1294}
1295
1296#ifdef STANDALONE
1297
1298int vstprintf (CHAR_T *buffer, size_t n, const CHAR_T *format, va_list arg_ptr)
1299{
1300 FILE trick;
1301 int result;
1302
1303 if (n > INT_MAX)
1304 return EOF;
1305 trick.__uVersion = _FILE_STDIO_VERSION;
1306 trick._buffer = (char *) buffer;
1307 trick._ptr = (char *) buffer;
1308 trick._rcount = 0;
1309 trick._wcount = n != 0 ? ((int)n - 1) * sizeof(CHAR_T) : 0;
1310 trick._handle = -1;
1311 trick._flags = _IOOPEN|_IOSPECIAL|_IOBUFUSER|_IOWRT;
1312 trick._buf_size = ((int)n) * sizeof(CHAR_T);
1313 trick._flush = NULL;
1314 trick._ungetc_count = 0;
1315 trick._mbstate = 0;
1316 _fmutex_dummy(&trick.__u.__fsem);
1317 result = NAME(_output) (&trick, format, arg_ptr);
1318 if (n != 0)
1319 *trick._ptr = 0;
1320 return result;
1321}
1322
1323int stprintf (CHAR_T *buffer, size_t n, const CHAR_T *format, ...)
1324{
1325 va_list arg_ptr;
1326 FILE trick;
1327 int result;
1328
1329 if (n > INT_MAX)
1330 return EOF;
1331 va_start (arg_ptr, format);
1332 trick.__uVersion = _FILE_STDIO_VERSION;
1333 trick._buffer = (char *) buffer;
1334 trick._ptr = (char *) buffer;
1335 trick._rcount = 0;
1336 trick._wcount = n != 0 ? ((int)n - 1) * sizeof(CHAR_T) : 0;
1337 trick._handle = -1;
1338 trick._flags = _IOOPEN|_IOSPECIAL|_IOBUFUSER|_IOWRT;
1339 trick._buf_size = ((int)n) * sizeof(CHAR_T);
1340 trick._flush = NULL;
1341 trick._ungetc_count = 0;
1342 trick._mbstate = 0;
1343 _fmutex_dummy(&trick.__u.__fsem);
1344 result = NAME(_output) (&trick, format, arg_ptr);
1345 if (n != 0)
1346 *trick._ptr = 0;
1347 va_end (arg_ptr);
1348 return result;
1349}
1350
1351int main ()
1352{
1353 printf ("Locale is set to: %s\n", setlocale (LC_ALL, "ru_RU"));
1354
1355 CHAR_T buf[256];
1356 CMEMSET (buf, 0, SIZEOF_ARRAY (buf));
1357
1358 stprintf (buf, SIZEOF_ARRAY (buf), CHAR_L("Test 0x%08X (%d) {%lf} {%F} {%lF} [%s] [%S] [[%c]] [[%C]]\n"), 0x12345, -12345, 123.45, -0.1e-5, NAN, "char", L"wchar_t", 0xEF /* Russian YA in CP866 */, 0x044F /* Russian YA in Unicode */ );
1359
1360 char fn [PATH_MAX - 5];
1361 _execname (fn, sizeof (fn));
1362 strcat (fn, ".out");
1363 FILE *f = fopen (fn, "wb");
1364 fwrite (buf, 1, sizeof(buf), f);
1365 fclose (f);
1366
1367 return 0;
1368}
1369
1370#endif