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