OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libquadmath/] [printf/] [quadmath-printf.c] - Blame information for rev 792

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 740 jeremybenn
/* GCC Quad-Precision Math Library
2
   Copyright (C) 2011 Free Software Foundation, Inc.
3
   Written by Jakub Jelinek  <jakub@redhat.com>
4
 
5
This file is part of the libquadmath library.
6
Libquadmath is free software; you can redistribute it and/or
7
modify it under the terms of the GNU Library General Public
8
License as published by the Free Software Foundation; either
9
version 2 of the License, or (at your option) any later version.
10
 
11
Libquadmath is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
Library General Public License for more details.
15
 
16
You should have received a copy of the GNU Library General Public
17
License along with libquadmath; see the file COPYING.LIB.  If
18
not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
19
Boston, MA 02110-1301, USA.  */
20
 
21
#include <config.h>
22
#include <stdarg.h>
23
#include <string.h>
24
#include <stdio.h>
25
#include "quadmath-printf.h"
26
 
27
/* Read a simple integer from a string and update the string pointer.
28
   It is assumed that the first character is a digit.  */
29
static unsigned int
30
read_int (const char **pstr)
31
{
32
  unsigned int retval = (unsigned char) **pstr - '0';
33
 
34
  while (isdigit ((unsigned char) *++(*pstr)))
35
    {
36
      retval *= 10;
37
      retval += (unsigned char) **pstr - '0';
38
    }
39
 
40
  return retval;
41
}
42
 
43
#define PADSIZE 16
44
static char const blanks[PADSIZE] =
45
{' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
46
static char const zeroes[PADSIZE] =
47
{'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
48
static wchar_t const wblanks[PADSIZE] =
49
{
50
  L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '),
51
  L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' ')
52
};
53
static wchar_t const wzeroes[PADSIZE] =
54
{
55
  L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'),
56
  L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0')
57
};
58
 
59
attribute_hidden size_t
60
__quadmath_do_pad (struct __quadmath_printf_file *fp, int wide, int c,
61
                   size_t n)
62
{
63
  ssize_t i;
64
  char padbuf[PADSIZE];
65
  wchar_t wpadbuf[PADSIZE];
66
  const char *padstr;
67
  size_t w, written = 0;
68
  if (wide)
69
    {
70
      if (c == ' ')
71
        padstr = (const char *) wblanks;
72
      else if (c == '0')
73
        padstr = (const char *) wzeroes;
74
      else
75
        {
76
          padstr = (const char *) wpadbuf;
77
          for (i = 0; i < PADSIZE; i++)
78
            wpadbuf[i] = c;
79
        }
80
    }
81
  else
82
    {
83
      if (c == ' ')
84
        padstr = blanks;
85
      else if (c == '0')
86
        padstr = zeroes;
87
      else
88
        {
89
          padstr = (const char *) padbuf;
90
          for (i = 0; i < PADSIZE; i++)
91
            padbuf[i] = c;
92
        }
93
    }
94
  for (i = n; i >= PADSIZE; i -= PADSIZE)
95
    {
96
      w = PUT (fp, (char *) padstr, PADSIZE);
97
      written += w;
98
      if (w != PADSIZE)
99
        return written;
100
    }
101
  if (i > 0)
102
    {
103
      w = PUT (fp, (char *) padstr, i);
104
      written += w;
105
    }
106
  return written;
107
}
108
 
109
/* This is a stripped down version of snprintf, which just handles
110
   a single %eEfFgGaA format entry with Q modifier.  % has to be
111
   the first character of the format string, no $ can be used.  */
112
int
113
quadmath_snprintf (char *str, size_t size, const char *format, ...)
114
{
115
  struct printf_info info;
116
  va_list ap;
117
  __float128 fpnum, *fpnum_addr = &fpnum, **fpnum_addr2 = &fpnum_addr;
118
  struct __quadmath_printf_file qfp;
119
 
120
  if (*format++ != '%')
121
    return -1;
122
 
123
  /* Clear information structure.  */
124
  memset (&info, '\0', sizeof info);
125
  /* info.alt = 0;
126
  info.space = 0;
127
  info.left = 0;
128
  info.showsign = 0;
129
  info.group = 0;
130
  info.i18n = 0;
131
  info.extra = 0; */
132
  info.pad = ' ';
133
  /* info.wide = 0; */
134
 
135
  /* Check for spec modifiers.  */
136
  do
137
    {
138
      switch (*format)
139
        {
140
        case ' ':
141
          /* Output a space in place of a sign, when there is no sign.  */
142
          info.space = 1;
143
          continue;
144
        case '+':
145
          /* Always output + or - for numbers.  */
146
          info.showsign = 1;
147
          continue;
148
        case '-':
149
          /* Left-justify things.  */
150
          info.left = 1;
151
          continue;
152
        case '#':
153
          /* Use the "alternate form":
154
             Hex has 0x or 0X, FP always has a decimal point.  */
155
          info.alt = 1;
156
          continue;
157
        case '0':
158
          /* Pad with 0s.  */
159
          info.pad = '0';
160
          continue;
161
        case '\'':
162
          /* Show grouping in numbers if the locale information
163
             indicates any.  */
164
          info.group = 1;
165
          continue;
166
        case 'I':
167
          /* Use the internationalized form of the output.  Currently
168
             means to use the `outdigits' of the current locale.  */
169
          info.i18n = 1;
170
          continue;
171
        default:
172
          break;
173
        }
174
      break;
175
    }
176
  while (*++format);
177
 
178
  if (info.left)
179
    info.pad = ' ';
180
 
181
  va_start (ap, format);
182
 
183
  /* Get the field width.  */
184
  /* info.width = 0; */
185
  if (*format == '*')
186
    {
187
      /* The field width is given in an argument.
188
         A negative field width indicates left justification.  */
189
      ++format;
190
      info.width = va_arg (ap, int);
191
    }
192
  else if (isdigit (*format))
193
    /* Constant width specification.  */
194
    info.width = read_int (&format);
195
 
196
  /* Get the precision.  */
197
  /* -1 means none given; 0 means explicit 0.  */
198
  info.prec = -1;
199
  if (*format == '.')
200
    {
201
      ++format;
202
      if (*format == '*')
203
        {
204
          /* The precision is given in an argument.  */
205
          ++format;
206
 
207
          info.prec = va_arg (ap, int);
208
        }
209
      else if (isdigit (*format))
210
        info.prec = read_int (&format);
211
      else
212
        /* "%.?" is treated like "%.0?".  */
213
        info.prec = 0;
214
    }
215
 
216
  /* Check for type modifiers.  */
217
  /* info.is_long_double = 0;
218
  info.is_short = 0;
219
  info.is_long = 0;
220
  info.is_char = 0;
221
  info.user = 0; */
222
 
223
  /* We require Q modifier.  */
224
  if (*format++ != 'Q')
225
    {
226
      va_end (ap);
227
      return -1;
228
    }
229
 
230
  /* Get the format specification.  */
231
  info.spec = (wchar_t) *format++;
232
  if (info.spec == L_('\0') || *format != '\0')
233
    {
234
      va_end (ap);
235
      return -1;
236
    }
237
 
238
  switch (info.spec)
239
    {
240
    case L_('e'):
241
    case L_('E'):
242
    case L_('f'):
243
    case L_('F'):
244
    case L_('g'):
245
    case L_('G'):
246
    case L_('a'):
247
    case L_('A'):
248
      break;
249
    default:
250
      va_end (ap);
251
      return -1;
252
    }
253
 
254
  fpnum = va_arg (ap, __float128);
255
  va_end (ap);
256
 
257
  qfp.fp = NULL;
258
  qfp.str = str;
259
  qfp.size = size ? size - 1 : 0;
260
  qfp.len = 0;
261
  qfp.file_p = 0;
262
 
263
  if (info.spec == L_('a') || info.spec == L_('A'))
264
    __quadmath_printf_fphex (&qfp, &info, (const void *const *)&fpnum_addr2);
265
  else
266
    __quadmath_printf_fp (&qfp, &info, (const void *const *)&fpnum_addr2);
267
 
268
  if (size)
269
    *qfp.str = '\0';
270
 
271
  return qfp.len;
272
}
273
 
274
#ifdef HAVE_PRINTF_HOOKS
275
static int pa_flt128;
276
int mod_Q attribute_hidden;
277
 
278
static void
279
flt128_va (void *mem, va_list *ap)
280
{
281
  __float128 d = va_arg (*ap, __float128);
282
  memcpy (mem, &d, sizeof (d));
283
}
284
 
285
static int
286
flt128_ais (const struct printf_info *info, size_t n __attribute__ ((unused)),
287
            int *argtype, int *size)
288
{
289
  if (info->user & mod_Q)
290
    {
291
      argtype[0] = pa_flt128;
292
      size[0] = sizeof (__float128);
293
      return 1;
294
    }
295
#if __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 13)
296
  /* Workaround bug in glibc printf hook handling.  */
297
  size[0] = -1;
298
  switch (info->spec)
299
    {
300
    case L_('i'):
301
    case L_('d'):
302
    case L_('u'):
303
    case L_('o'):
304
    case L_('X'):
305
    case L_('x'):
306
#if __LONG_MAX__ != __LONG_LONG_MAX__
307
      if (info->is_long_double)
308
        argtype[0] = PA_INT|PA_FLAG_LONG_LONG;
309
      else
310
#endif
311
      if (info->is_long)
312
        argtype[0] = PA_INT|PA_FLAG_LONG;
313
      else if (info->is_short)
314
        argtype[0] = PA_INT|PA_FLAG_SHORT;
315
      else if (info->is_char)
316
        argtype[0] = PA_CHAR;
317
      else
318
        argtype[0] = PA_INT;
319
      return 1;
320
    case L_('e'):
321
    case L_('E'):
322
    case L_('f'):
323
    case L_('F'):
324
    case L_('g'):
325
    case L_('G'):
326
    case L_('a'):
327
    case L_('A'):
328
      if (info->is_long_double)
329
        argtype[0] = PA_DOUBLE|PA_FLAG_LONG_DOUBLE;
330
      else
331
        argtype[0] = PA_DOUBLE;
332
      return 1;
333
    case L_('c'):
334
      argtype[0] = PA_CHAR;
335
      return 1;
336
    case L_('C'):
337
      argtype[0] = PA_WCHAR;
338
      return 1;
339
    case L_('s'):
340
      argtype[0] = PA_STRING;
341
      return 1;
342
    case L_('S'):
343
      argtype[0] = PA_WSTRING;
344
      return 1;
345
    case L_('p'):
346
      argtype[0] = PA_POINTER;
347
      return 1;
348
    case L_('n'):
349
      argtype[0] = PA_INT|PA_FLAG_PTR;
350
      return 1;
351
 
352
    case L_('m'):
353
    default:
354
      /* An unknown spec will consume no args.  */
355
      return 0;
356
    }
357
#endif
358
  return -1;
359
}
360
 
361
static int
362
flt128_printf_fp (FILE *fp, const struct printf_info *info,
363
                  const void *const *args)
364
{
365
  struct __quadmath_printf_file qpf
366
    = { .fp = fp, .str = NULL, .size = 0, .len = 0, .file_p = 1 };
367
 
368
  if ((info->user & mod_Q) == 0)
369
    return -2;
370
 
371
  return __quadmath_printf_fp (&qpf, info, args);
372
}
373
 
374
static int
375
flt128_printf_fphex (FILE *fp, const struct printf_info *info,
376
                     const void *const *args)
377
{
378
  struct __quadmath_printf_file qpf
379
    = { .fp = fp, .str = NULL, .size = 0, .len = 0, .file_p = 1 };
380
 
381
  if ((info->user & mod_Q) == 0)
382
    return -2;
383
 
384
  return __quadmath_printf_fphex (&qpf, info, args);
385
}
386
 
387
__attribute__((constructor)) static void
388
register_printf_flt128 (void)
389
{
390
  pa_flt128 = register_printf_type (flt128_va);
391
  if (pa_flt128 == -1)
392
    return;
393
  mod_Q = register_printf_modifier (L_("Q"));
394
  if (mod_Q == -1)
395
    return;
396
  register_printf_specifier ('f', flt128_printf_fp, flt128_ais);
397
  register_printf_specifier ('F', flt128_printf_fp, flt128_ais);
398
  register_printf_specifier ('e', flt128_printf_fp, flt128_ais);
399
  register_printf_specifier ('E', flt128_printf_fp, flt128_ais);
400
  register_printf_specifier ('g', flt128_printf_fp, flt128_ais);
401
  register_printf_specifier ('G', flt128_printf_fp, flt128_ais);
402
  register_printf_specifier ('a', flt128_printf_fphex, flt128_ais);
403
  register_printf_specifier ('A', flt128_printf_fphex, flt128_ais);
404
}
405
 
406
__attribute__((destructor)) static void
407
unregister_printf_flt128 (void)
408
{
409
  /* No way to unregister printf type and modifier currently,
410
     and only one printf specifier can be registered right now.  */
411
  if (pa_flt128 == -1 || mod_Q == -1)
412
    return;
413
  register_printf_specifier ('f', NULL, NULL);
414
  register_printf_specifier ('F', NULL, NULL);
415
  register_printf_specifier ('e', NULL, NULL);
416
  register_printf_specifier ('E', NULL, NULL);
417
  register_printf_specifier ('g', NULL, NULL);
418
  register_printf_specifier ('G', NULL, NULL);
419
  register_printf_specifier ('a', NULL, NULL);
420
  register_printf_specifier ('A', NULL, NULL);
421
}
422
#endif

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.