[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     ! 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>