[BACK]Return to repl-vsnprintf.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib / gmp / printf

Annotation of OpenXM_contrib/gmp/printf/repl-vsnprintf.c, Revision 1.1.1.1

1.1       ohara       1: /* __gmp_replacement_vsnprintf -- for systems which don't have vsnprintf, or
                      2:    only have a broken one.
                      3:
                      4:    THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
                      5:    CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
                      6:    FUTURE GNU MP RELEASES.
                      7:
                      8: Copyright 2001, 2002 Free Software Foundation, Inc.
                      9:
                     10: This file is part of the GNU MP Library.
                     11:
                     12: The GNU MP Library is free software; you can redistribute it and/or modify
                     13: it under the terms of the GNU Lesser General Public License as published by
                     14: the Free Software Foundation; either version 2.1 of the License, or (at your
                     15: option) any later version.
                     16:
                     17: The GNU MP Library is distributed in the hope that it will be useful, but
                     18: WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
                     19: or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
                     20: License for more details.
                     21:
                     22: You should have received a copy of the GNU Lesser General Public License
                     23: along with the GNU MP Library; see the file COPYING.LIB.  If not, write to
                     24: the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
                     25: MA 02111-1307, USA. */
                     26:
                     27: #define _GNU_SOURCE    /* for strnlen prototype */
                     28:
                     29: #include "config.h"
                     30:
                     31: #if HAVE_STDARG
                     32: #include <stdarg.h>
                     33: #else
                     34: #include <varargs.h>
                     35: #endif
                     36:
                     37: #include <ctype.h>     /* for isdigit */
                     38: #include <float.h>     /* for DBL_MAX_10_EXP etc */
                     39: #include <stddef.h>    /* for ptrdiff_t */
                     40: #include <string.h>
                     41: #include <stdio.h>     /* for NULL */
                     42: #include <stdlib.h>
                     43:
                     44: #if HAVE_INTTYPES_H
                     45: # include <inttypes.h> /* for intmax_t */
                     46: #else
                     47: # if HAVE_STDINT_H
                     48: #  include <stdint.h>
                     49: # endif
                     50: #endif
                     51:
                     52: #if HAVE_SYS_TYPES_H
                     53: #include <sys/types.h> /* for quad_t */
                     54: #endif
                     55:
                     56: #include "gmp.h"
                     57: #include "gmp-impl.h"
                     58:
                     59:
                     60: /* Autoconf notes that AIX 4.3 has a broken strnlen, but fortunately it
                     61:    doesn't affect us since __gmp_replacement_vsnprintf is not required on
                     62:    that system.  */
                     63: #if ! HAVE_STRNLEN
                     64: static size_t
                     65: strnlen (const char *s, size_t n)
                     66: {
                     67:   size_t  i;
                     68:   for (i = 0; i < n; i++)
                     69:     if (s[i] == '\0')
                     70:       break;
                     71:   return i;
                     72: }
                     73: #endif
                     74:
                     75:
                     76: /* The approach here is to parse the fmt string, and decide how much space
                     77:    it requires, then use vsprintf into a big enough buffer.  The space
                     78:    calculated isn't an exact amount, but it's certainly no less than
                     79:    required.
                     80:
                     81:    This code was inspired by GNU libiberty/vasprintf.c but we support more
                     82:    datatypes, when available.
                     83:
                     84:    mingw32 - doesn't have vsnprintf, it seems.  Because gcc is used a full
                     85:        set of types are available, but "long double" is just a plain IEEE
                     86:        64-bit "double", so we avoid the big 15-bit exponent estimate
                     87:        (LDBL_MAX_EXP_10 is defined).  */
                     88:
                     89: int
                     90: __gmp_replacement_vsnprintf (char *buf, size_t buf_size,
                     91:                              const char *orig_fmt, va_list orig_ap)
                     92: {
                     93:   va_list     ap;
                     94:   const char  *fmt;
                     95:   size_t      total_width, integer_sizeof, floating_sizeof, len;
                     96:   char        fchar, type;
                     97:   int         width, prec, seen_prec, double_digits, long_double_digits;
                     98:   int         *value;
                     99:
                    100:   /* preserve orig_ap for use after size estimation */
                    101:   va_copy (ap, orig_ap);
                    102:
                    103:   fmt = orig_fmt;
                    104:   total_width = strlen (fmt) + 1;   /* 1 extra for the '\0' */
                    105:
                    106:   integer_sizeof = sizeof (long);
                    107: #if HAVE_LONG_LONG
                    108:   integer_sizeof = MAX (integer_sizeof, sizeof (long long));
                    109: #endif
                    110: #if HAVE_QUAD_T
                    111:   integer_sizeof = MAX (integer_sizeof, sizeof (quad_t));
                    112: #endif
                    113:
                    114:   floating_sizeof = sizeof (double);
                    115: #if HAVE_LONG_DOUBLE
                    116:   floating_sizeof = MAX (floating_sizeof, sizeof (long double));
                    117: #endif
                    118:
                    119:   /* IEEE double or VAX G floats have an 11 bit exponent, so the default is
                    120:      a maximum 308 decimal digits.  VAX D floats have only an 8 bit
                    121:      exponent, but we don't bother trying to detect that directly.  */
                    122:   double_digits = 308;
                    123: #ifdef DBL_MAX_10_EXP
                    124:   /* but case prefer a value the compiler says */
                    125:   double_digits = DBL_MAX_10_EXP;
                    126: #endif
                    127:
                    128:   /* IEEE 128-bit quad, Intel 80-bit temporary, or VAX H floats all have 15
                    129:      bit exponents, so the default is a maximum 4932 decimal digits.  */
                    130:   long_double_digits = 4932;
                    131:   /* but if double == long double, then go with that size */
                    132: #if HAVE_LONG_DOUBLE
                    133:   if (sizeof (double) == sizeof (long double))
                    134:     long_double_digits = double_digits;
                    135: #endif
                    136: #ifdef LDBL_MAX_10_EXP
                    137:   /* but in any case prefer a value the compiler says */
                    138:   long_double_digits = LDBL_MAX_10_EXP;
                    139: #endif
                    140:
                    141:   for (;;)
                    142:     {
                    143:       fmt = strchr (fmt, '%');
                    144:       if (fmt == NULL)
                    145:         break;
                    146:       fmt++;
                    147:
                    148:       type = '\0';
                    149:       width = 0;
                    150:       prec = 6;
                    151:       seen_prec = 0;
                    152:       value = &width;
                    153:
                    154:       for (;;)
                    155:         {
                    156:           fchar = *fmt++;
                    157:           switch (fchar) {
                    158:
                    159:           case 'c':
                    160:             /* char, already accounted for by strlen(fmt) */
                    161:             goto next;
                    162:
                    163:           case 'd':
                    164:           case 'i':
                    165:           case 'o':
                    166:           case 'x':
                    167:           case 'X':
                    168:           case 'u':
                    169:             /* at most 3 digits per byte in hex, dec or octal, plus a sign */
                    170:             total_width += 3 * integer_sizeof + 1;
                    171:
                    172:             switch (type) {
                    173:             case 'j':
                    174:               /* Let's assume uintmax_t is the same size as intmax_t. */
                    175: #if HAVE_INTMAX_T
                    176:               (void) va_arg (ap, intmax_t);
                    177: #else
                    178:               ASSERT_FAIL (intmax_t not available);
                    179: #endif
                    180:               break;
                    181:             case 'l':
                    182:               (void) va_arg (ap, long);
                    183:               break;
                    184:             case 'L':
                    185: #if HAVE_LONG_LONG
                    186:               (void) va_arg (ap, long long);
                    187: #else
                    188:               ASSERT_FAIL (long long not available);
                    189: #endif
                    190:               break;
                    191:             case 'q':
                    192:               /* quad_t is probably the same as long long, but let's treat
                    193:                  it separately just to be sure.  Also let's assume u_quad_t
                    194:                  will be the same size as quad_t.  */
                    195: #if HAVE_QUAD_T
                    196:               (void) va_arg (ap, quad_t);
                    197: #else
                    198:               ASSERT_FAIL (quad_t not available);
                    199: #endif
                    200:               break;
                    201:             case 't':
                    202: #if HAVE_PTRDIFF_T
                    203:               (void) va_arg (ap, ptrdiff_t);
                    204: #else
                    205:               ASSERT_FAIL (ptrdiff_t not available);
                    206: #endif
                    207:               break;
                    208:             case 'z':
                    209:               (void) va_arg (ap, size_t);
                    210:               break;
                    211:             default:
                    212:               /* default is an "int", and this includes h=short and hh=char
                    213:                  since they're promoted to int in a function call */
                    214:               (void) va_arg (ap, int);
                    215:               break;
                    216:             }
                    217:             goto next;
                    218:
                    219:           case 'E':
                    220:           case 'e':
                    221:           case 'G':
                    222:           case 'g':
                    223:             /* Requested decimals, sign, point and e, plus an overestimate
                    224:                of exponent digits (the assumption is all the float is
                    225:                exponent!).  */
                    226:             total_width += prec + 3 + floating_sizeof * 3;
                    227:             if (type == 'L')
                    228:               {
                    229: #if HAVE_LONG_DOUBLE
                    230:                 (void) va_arg (ap, long double);
                    231: #else
                    232:                 ASSERT_FAIL (long double not available);
                    233: #endif
                    234:               }
                    235:             else
                    236:              (void) va_arg (ap, double);
                    237:             break;
                    238:
                    239:           case 'f':
                    240:             /* Requested decimals, sign and point, and a margin for error,
                    241:                then add the maximum digits that can be in the integer part,
                    242:                based on the maximum exponent value. */
                    243:             total_width += prec + 2 + 10;
                    244:             if (type == 'L')
                    245:               {
                    246: #if HAVE_LONG_DOUBLE
                    247:                 (void) va_arg (ap, long double);
                    248:                 total_width += long_double_digits;
                    249: #else
                    250:                 ASSERT_FAIL (long double not available);
                    251: #endif
                    252:               }
                    253:             else
                    254:               {
                    255:                 (void) va_arg (ap, double);
                    256:                 total_width += double_digits;
                    257:               }
                    258:             break;
                    259:
                    260:           case 'h':  /* short or char */
                    261:           case 'j':  /* intmax_t */
                    262:           case 'L':  /* long long or long double */
                    263:           case 'q':  /* quad_t */
                    264:           case 't':  /* ptrdiff_t */
                    265:           set_type:
                    266:             type = fchar;
                    267:             break;
                    268:
                    269:           case 'l':
                    270:             /* long or long long */
                    271:             if (type != 'l')
                    272:               goto set_type;
                    273:             type = 'L';   /* "ll" means "L" */
                    274:             break;
                    275:
                    276:           case 'n':
                    277:             /* bytes written, no output as such */
                    278:             (void) va_arg (ap, void *);
                    279:             goto next;
                    280:
                    281:           case 's':
                    282:             /* If no precision was given, then determine the string length
                    283:                and put it there, to be added to the total under "next".  If
                    284:                a precision was given then that's already the maximum from
                    285:                this field, but see whether the string is shorter than that,
                    286:                in case the limit was very big.  */
                    287:             {
                    288:               const char  *s = va_arg (ap, const char *);
                    289:               prec = (seen_prec ? strnlen (s, prec) : strlen (s));
                    290:             }
                    291:             goto next;
                    292:
                    293:           case 'p':
                    294:             /* pointer, let's assume at worst it's octal with some padding */
                    295:             (void) va_arg (ap, const void *);
                    296:             total_width += 3 * sizeof (void *) + 16;
                    297:             goto next;
                    298:
                    299:           case '%':
                    300:             /* literal %, already accounted for by strlen(fmt) */
                    301:             goto next;
                    302:
                    303:           case '#':
                    304:             /* showbase, at most 2 for "0x" */
                    305:             total_width += 2;
                    306:             break;
                    307:
                    308:           case '+':
                    309:           case ' ':
                    310:             /* sign, already accounted for under numerics */
                    311:             break;
                    312:
                    313:           case '-':
                    314:             /* left justify, no effect on total width */
                    315:             break;
                    316:
                    317:           case '.':
                    318:             seen_prec = 1;
                    319:             value = &prec;
                    320:             break;
                    321:
                    322:           case '*':
                    323:             {
                    324:               /* negative width means left justify which can be ignored,
                    325:                  negative prec would be invalid, just use absolute value */
                    326:               int n = va_arg (ap, int);
                    327:               *value = ABS (n);
                    328:             }
                    329:             break;
                    330:
                    331:           case '0': case '1': case '2': case '3': case '4':
                    332:           case '5': case '6': case '7': case '8': case '9':
                    333:             /* process all digits to form a value */
                    334:             {
                    335:               int  n = 0;
                    336:               do {
                    337:                 n = n * 10 + (fchar-'0');
                    338:                 fchar = *fmt++;
                    339:               } while (isascii (fchar) && isdigit (fchar));
                    340:               fmt--; /* unget the non-digit */
                    341:               *value = n;
                    342:             }
                    343:             break;
                    344:
                    345:           default:
                    346:             /* incomplete or invalid % sequence */
                    347:             ASSERT (0);
                    348:             goto next;
                    349:           }
                    350:         }
                    351:
                    352:     next:
                    353:       total_width += width;
                    354:       total_width += prec;
                    355:     }
                    356:
                    357:   if (total_width <= buf_size)
                    358:     {
                    359:       vsprintf (buf, orig_fmt, orig_ap);
                    360:       len = strlen (buf);
                    361:     }
                    362:   else
                    363:     {
                    364:       char  *s;
                    365:
                    366:       s = __GMP_ALLOCATE_FUNC_TYPE (total_width, char);
                    367:       vsprintf (s, orig_fmt, orig_ap);
                    368:       len = strlen (s);
                    369:       if (buf_size != 0)
                    370:         {
                    371:           size_t  copylen = MIN (len, buf_size-1);
                    372:           memcpy (buf, s, copylen);
                    373:           buf[copylen] = '\0';
                    374:         }
                    375:       (*__gmp_free_func) (s, total_width);
                    376:     }
                    377:
                    378:   /* If total_width was somehow wrong then chances are we've already
                    379:      clobbered memory, but maybe this check will still work.  */
                    380:   ASSERT_ALWAYS (len < total_width);
                    381:
                    382:   return len;
                    383: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>