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

Annotation of OpenXM_contrib/gmp/printf/doprntf.c, Revision 1.1

1.1     ! ohara       1: /* __gmp_doprnt_mpf -- mpf formatted output.
        !             2:
        !             3:    THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
        !             4:    CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
        !             5:    FUTURE GNU MP RELEASES.
        !             6:
        !             7: Copyright 2001, 2002 Free Software Foundation, Inc.
        !             8:
        !             9: This file is part of the GNU MP Library.
        !            10:
        !            11: The GNU MP Library is free software; you can redistribute it and/or modify
        !            12: it under the terms of the GNU Lesser General Public License as published by
        !            13: the Free Software Foundation; either version 2.1 of the License, or (at your
        !            14: option) any later version.
        !            15:
        !            16: The GNU MP Library is distributed in the hope that it will be useful, but
        !            17: WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
        !            18: or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
        !            19: License for more details.
        !            20:
        !            21: You should have received a copy of the GNU Lesser General Public License
        !            22: along with the GNU MP Library; see the file COPYING.LIB.  If not, write to
        !            23: the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
        !            24: MA 02111-1307, USA. */
        !            25:
        !            26: #include "config.h"
        !            27:
        !            28: #if HAVE_STDARG
        !            29: #include <stdarg.h>    /* for va_list and hence doprnt_funs_t */
        !            30: #else
        !            31: #include <varargs.h>
        !            32: #endif
        !            33:
        !            34: #include <ctype.h>
        !            35: #include <string.h>
        !            36: #include <stdio.h>
        !            37: #include <stdlib.h>
        !            38:
        !            39: #if HAVE_LOCALE_H
        !            40: #include <locale.h>    /* for localeconv */
        !            41: #endif
        !            42:
        !            43: #include "gmp.h"
        !            44: #include "gmp-impl.h"
        !            45:
        !            46:
        !            47: /* change this to "#define TRACE(x) x" for diagnostics */
        !            48: #define TRACE(x)
        !            49:
        !            50:
        !            51: /* The separate of __gmp_doprnt_float_digits and __gmp_doprnt_float is so
        !            52:    some C++ can do the mpf_get_str and release it in case of an exception */
        !            53:
        !            54: #define DIGIT_VALUE(c)                  \
        !            55:   (isdigit (c)   ? (c) - '0'            \
        !            56:    : islower (c) ? (c) - 'a' + 10       \
        !            57:    :               (c) - 'A' + 10)
        !            58:
        !            59: int
        !            60: __gmp_doprnt_mpf (const struct doprnt_funs_t *funs,
        !            61:                   void *data,
        !            62:                   const struct doprnt_params_t *p,
        !            63:                   mpf_srcptr f)
        !            64: {
        !            65:   int         prec, ndigits, free_size, len, newlen, justify, justlen, explen;
        !            66:   int         showbaselen, sign, signlen, intlen, intzeros, pointlen;
        !            67:   int         fraczeros, fraclen, preczeros;
        !            68:   char        *s, *free_ptr;
        !            69:   mp_exp_t    exp;
        !            70:   char        exponent[BITS_PER_MP_LIMB + 10];
        !            71:   const char  *showbase;
        !            72:   const char  *point;
        !            73:   int         retval = 0;
        !            74:
        !            75:   TRACE (printf ("__gmp_doprnt_float\n");
        !            76:          printf ("  conv=%d prec=%d\n", p->conv, p->prec));
        !            77:
        !            78:   prec = p->prec;
        !            79:   if (prec <= -1)
        !            80:     {
        !            81:       /* all digits */
        !            82:       ndigits = 0;
        !            83:
        !            84:       /* arrange the fixed/scientific decision on a "prec" implied by how
        !            85:          many significant digits there are */
        !            86:       if (p->conv == DOPRNT_CONV_GENERAL)
        !            87:         MPF_SIGNIFICANT_DIGITS (prec, PREC(f), ABS(p->base));
        !            88:     }
        !            89:   else
        !            90:     {
        !            91:       switch (p->conv) {
        !            92:       case DOPRNT_CONV_FIXED:
        !            93:         /* Precision is digits after the radix point.  Try not to generate
        !            94:            too many more than will actually be required.  If f>=1 then
        !            95:            overestimate the integer part, and add prec.  If f<1 then
        !            96:            underestimate the zeros between the radix point and the first
        !            97:            digit and subtract that from prec.  In either case add 2 so the
        !            98:            round to nearest can be applied accurately.  */
        !            99:         ndigits = prec + 2
        !           100:           + EXP(f) * (__mp_bases[ABS(p->base)].chars_per_limb + (EXP(f)>=0));
        !           101:         ndigits = MAX (ndigits, 1);
        !           102:         break;
        !           103:
        !           104:       case DOPRNT_CONV_SCIENTIFIC:
        !           105:         /* precision is digits after the radix point, and there's one digit
        !           106:            before */
        !           107:         ndigits = prec + 1;
        !           108:         break;
        !           109:
        !           110:       default:
        !           111:         ASSERT (0);
        !           112:         /*FALLTHRU*/
        !           113:
        !           114:       case DOPRNT_CONV_GENERAL:
        !           115:         /* precision is total digits, but be sure to ask mpf_get_str for at
        !           116:            least 1, not 0 */
        !           117:         ndigits = MAX (prec, 1);
        !           118:         break;
        !           119:       }
        !           120:     }
        !           121:   TRACE (printf ("  ndigits %d\n", ndigits));
        !           122:
        !           123:   s = mpf_get_str (NULL, &exp, p->base, ndigits, f);
        !           124:   len = strlen (s);
        !           125:   free_ptr = s;
        !           126:   free_size = len + 1;
        !           127:   TRACE (printf ("  s   %s\n", s);
        !           128:          printf ("  exp %ld\n", exp);
        !           129:          printf ("  len %d\n", len));
        !           130:
        !           131:   /* For fixed mode check the ndigits formed above was in fact enough for
        !           132:      the integer part plus p->prec after the radix point. */
        !           133:   ASSERT ((p->conv == DOPRNT_CONV_FIXED && p->prec > -1)
        !           134:           ? ndigits >= MAX (1, exp + p->prec + 2) : 1);
        !           135:
        !           136:   sign = p->sign;
        !           137:   if (s[0] == '-')
        !           138:     {
        !           139:       sign = s[0];
        !           140:       s++, len--;
        !           141:     }
        !           142:   signlen = (sign != '\0');
        !           143:   TRACE (printf ("  sign %c  signlen %d\n", sign, signlen));
        !           144:
        !           145:   switch (p->conv) {
        !           146:   case DOPRNT_CONV_FIXED:
        !           147:     if (prec <= -1)
        !           148:       prec = MAX (0, len-exp);   /* retain all digits */
        !           149:
        !           150:     /* Truncate if necessary so fraction will be at most prec digits. */
        !           151:     ASSERT (prec >= 0);
        !           152:     newlen = exp + prec;
        !           153:     if (newlen < 0)
        !           154:       {
        !           155:         /* first non-zero digit is below target prec, and at least one zero
        !           156:            digit in between, so print zero */
        !           157:         len = 0;
        !           158:         exp = 0;
        !           159:       }
        !           160:     else if (len <= newlen)
        !           161:       {
        !           162:         /* already got few enough digits */
        !           163:       }
        !           164:     else
        !           165:       {
        !           166:         /* discard excess digits and round to nearest */
        !           167:
        !           168:         const char  *num_to_text = (p->base >= 0
        !           169:                                     ? "0123456789abcdefghijklmnopqrstuvwxyz"
        !           170:                                     : "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ");
        !           171:         int  base = ABS(p->base);
        !           172:         int  n;
        !           173:
        !           174:         ASSERT (base <= 36);
        !           175:
        !           176:         len = newlen;
        !           177:         n = DIGIT_VALUE (s[len]);
        !           178:         TRACE (printf ("  rounding with %d\n", n));
        !           179:         if (n >= (base + 1) / 2)
        !           180:           {
        !           181:             /* propagate a carry */
        !           182:             for (;;)
        !           183:               {
        !           184:                 if (len == 0)
        !           185:                   {
        !           186:                     s[0] = '1';
        !           187:                     len = 1;
        !           188:                     exp++;
        !           189:                     break;
        !           190:                   }
        !           191:                 n = DIGIT_VALUE (s[len-1]);
        !           192:                 ASSERT (n >= 0 && n < base);
        !           193:                 n++;
        !           194:                 if (n != base)
        !           195:                   {
        !           196:                     TRACE (printf ("  storing now %d\n", n));
        !           197:                     s[len-1] = num_to_text[n];
        !           198:                     break;
        !           199:                   }
        !           200:                 len--;
        !           201:               }
        !           202:           }
        !           203:         else
        !           204:           {
        !           205:             /* truncate only, strip any trailing zeros now exposed */
        !           206:             while (len > 0 && s[len-1] == '0')
        !           207:               len--;
        !           208:           }
        !           209:
        !           210:         /* Can have newlen==0, in which case the truncate was just to check
        !           211:            for a carry turning it into "1".  If we're left with len==0 then
        !           212:            adjust exp to match.  */
        !           213:         if (len == 0)
        !           214:           exp = 0;
        !           215:       }
        !           216:
        !           217:   fixed:
        !           218:     ASSERT (len == 0 ? exp == 0 : 1);
        !           219:     if (exp <= 0)
        !           220:       {
        !           221:         TRACE (printf ("  fixed 0.000sss\n"));
        !           222:         intlen = 0;
        !           223:         intzeros = 1;
        !           224:         fraczeros = -exp;
        !           225:         fraclen = len;
        !           226:       }
        !           227:     else
        !           228:       {
        !           229:         TRACE (printf ("  fixed sss.sss or sss000\n"));
        !           230:         intlen = MIN (len, exp);
        !           231:         intzeros = exp - intlen;
        !           232:         fraczeros = 0;
        !           233:         fraclen = len - intlen;
        !           234:       }
        !           235:     explen = 0;
        !           236:     break;
        !           237:
        !           238:   case DOPRNT_CONV_SCIENTIFIC:
        !           239:     {
        !           240:       int   expval;
        !           241:       char  expsign;
        !           242:
        !           243:       if (prec <= -1)
        !           244:         prec = MAX (0, len-1);   /* retain all digits */
        !           245:
        !           246:     scientific:
        !           247:       TRACE (printf ("  scientific s.sss\n"));
        !           248:
        !           249:       intlen = MIN (1, len);
        !           250:       intzeros = (intlen == 0 ? 1 : 0);
        !           251:       fraczeros = 0;
        !           252:       fraclen = len - intlen;
        !           253:
        !           254:       expval = (exp-intlen);
        !           255:       if (p->exptimes4)
        !           256:         expval <<= 2;
        !           257:
        !           258:       /* Split out the sign since %o or %x in expfmt give negatives as twos
        !           259:          complement, not with a sign. */
        !           260:       expsign = (expval >= 0 ? '+' : '-');
        !           261:       expval = ABS (expval);
        !           262:
        !           263: #if HAVE_VSNPRINTF
        !           264:       explen = snprintf (exponent, sizeof(exponent),
        !           265:                          p->expfmt, expsign, expval);
        !           266:       /* test for < sizeof-1 since a glibc 2.0.x return of sizeof-1 might
        !           267:          mean truncation */
        !           268:       ASSERT (explen >= 0 && explen < sizeof(exponent)-1);
        !           269: #else
        !           270:       sprintf (exponent, p->expfmt, expsign, expval);
        !           271:       explen = strlen (exponent);
        !           272:       ASSERT (explen < sizeof(exponent));
        !           273: #endif
        !           274:       TRACE (printf ("  expfmt %s gives %s\n", p->expfmt, exponent));
        !           275:     }
        !           276:     break;
        !           277:
        !           278:   default:
        !           279:     ASSERT (0);
        !           280:     /*FALLTHRU*/  /* to stop variables looking uninitialized */
        !           281:
        !           282:   case DOPRNT_CONV_GENERAL:
        !           283:     /* The exponent for "scientific" will be exp-1, choose scientific if
        !           284:        this is < -4 or >= prec (and minimum 1 for prec).  For f==0 will have
        !           285:        exp==0 and get the desired "fixed".  This rule follows glibc.  For
        !           286:        fixed there's no need to truncate, the desired ndigits will already
        !           287:        be as required.  */
        !           288:     if (exp-1 < -4 || exp-1 >= MAX (1, prec))
        !           289:       goto scientific;
        !           290:     else
        !           291:       goto fixed;
        !           292:   }
        !           293:
        !           294:   TRACE (printf ("  intlen %d intzeros %d fraczeros %d fraclen %d\n",
        !           295:                  intlen, intzeros, fraczeros, fraclen));
        !           296:   ASSERT (p->prec <= -1
        !           297:           ? intlen + fraclen == strlen (s)
        !           298:           : intlen + fraclen <= strlen (s));
        !           299:
        !           300:   if (p->showtrailing)
        !           301:     {
        !           302:       /* Pad to requested precision with trailing zeros, for general this is
        !           303:          all digits, for fixed and scientific just the fraction.  */
        !           304:       preczeros = prec - (fraczeros + fraclen
        !           305:                           + (p->conv == DOPRNT_CONV_GENERAL
        !           306:                              ? intlen + intzeros : 0));
        !           307:       preczeros = MAX (0, preczeros);
        !           308:     }
        !           309:   else
        !           310:     preczeros = 0;
        !           311:   TRACE (printf ("  prec=%d showtrailing=%d, pad with preczeros %d\n",
        !           312:                  prec, p->showtrailing, preczeros));
        !           313:
        !           314:   /* radix point if needed, or if forced */
        !           315:   point = ".";
        !           316:   pointlen = ((fraczeros + fraclen + preczeros) != 0 || p->showpoint != 0);
        !           317: #if HAVE_LOCALECONV
        !           318:   if (pointlen)
        !           319:     {
        !           320:       point = localeconv()->decimal_point;
        !           321:       pointlen = strlen (point);
        !           322:     }
        !           323: #endif
        !           324:   TRACE (printf ("  point |%s|  pointlen %d\n", point, pointlen));
        !           325:
        !           326:   /* Notice the test for a non-zero value is done after any truncation for
        !           327:      DOPRNT_CONV_FIXED. */
        !           328:   showbase = NULL;
        !           329:   showbaselen = 0;
        !           330:   switch (p->showbase) {
        !           331:   default:
        !           332:     ASSERT (0);
        !           333:     /*FALLTHRU*/
        !           334:   case DOPRNT_SHOWBASE_NO:
        !           335:     break;
        !           336:   case DOPRNT_SHOWBASE_NONZERO:
        !           337:     if (intlen == 0 && fraclen == 0)
        !           338:       break;
        !           339:     /*FALLTHRU*/
        !           340:   case DOPRNT_SHOWBASE_YES:
        !           341:     switch (p->base) {
        !           342:     case 16:  showbase = "0x"; showbaselen = 2; break;
        !           343:     case -16: showbase = "0X"; showbaselen = 2; break;
        !           344:     case 8:   showbase = "0";  showbaselen = 1; break;
        !           345:     }
        !           346:     break;
        !           347:   }
        !           348:   TRACE (printf ("  showbase %s showbaselen %d\n",
        !           349:                  showbase == NULL ? "" : showbase, showbaselen));
        !           350:
        !           351:   /* left over field width */
        !           352:   justlen = p->width - (signlen + showbaselen + intlen + intzeros + pointlen
        !           353:                         + fraczeros + fraclen + preczeros + explen);
        !           354:   TRACE (printf ("  justlen %d fill 0x%X\n", justlen, p->fill));
        !           355:
        !           356:   justify = p->justify;
        !           357:   if (justlen <= 0) /* no justifying if exceed width */
        !           358:     justify = DOPRNT_JUSTIFY_NONE;
        !           359:
        !           360:   TRACE (printf ("  justify type %d  intlen %d pointlen %d fraclen %d\n",
        !           361:                  justify, intlen, pointlen, fraclen));
        !           362:
        !           363:   if (justify == DOPRNT_JUSTIFY_RIGHT)         /* pad for right */
        !           364:     DOPRNT_REPS (p->fill, justlen);
        !           365:
        !           366:   if (signlen)                                 /* sign */
        !           367:     DOPRNT_REPS (sign, 1);
        !           368:
        !           369:   DOPRNT_MEMORY_MAYBE (showbase, showbaselen); /* base */
        !           370:
        !           371:   if (justify == DOPRNT_JUSTIFY_INTERNAL)      /* pad for internal */
        !           372:     DOPRNT_REPS (p->fill, justlen);
        !           373:
        !           374:   DOPRNT_MEMORY (s, intlen);                   /* integer */
        !           375:   DOPRNT_REPS_MAYBE ('0', intzeros);
        !           376:
        !           377:   DOPRNT_MEMORY_MAYBE (point, pointlen);       /* point */
        !           378:
        !           379:   DOPRNT_REPS_MAYBE ('0', fraczeros);          /* frac */
        !           380:   DOPRNT_MEMORY_MAYBE (s+intlen, fraclen);
        !           381:
        !           382:   DOPRNT_REPS_MAYBE ('0', preczeros);          /* prec */
        !           383:
        !           384:   DOPRNT_MEMORY_MAYBE (exponent, explen);      /* exp */
        !           385:
        !           386:   if (justify == DOPRNT_JUSTIFY_LEFT)          /* pad for left */
        !           387:     DOPRNT_REPS (p->fill, justlen);
        !           388:
        !           389:  done:
        !           390:   (*__gmp_free_func) (free_ptr, free_size);
        !           391:   return retval;
        !           392:
        !           393:  error:
        !           394:   retval = -1;
        !           395:   goto done;
        !           396: }

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