[BACK]Return to vsnprintf.c CVS log [TXT][DIR] Up to [local] / ircnowd / src / portab

Annotation of ircnowd/src/portab/vsnprintf.c, Revision 1.1

1.1     ! tomglok     1: /*
        !             2:  * ngIRCd -- The Next Generation IRC Daemon
        !             3:  * Copyright (c)2001,2002 by Alexander Barton (alex@barton.de)
        !             4:  *
        !             5:  * This program is free software; you can redistribute it and/or modify
        !             6:  * it under the terms of the GNU General Public License as published by
        !             7:  * the Free Software Foundation; either version 2 of the License, or
        !             8:  * (at your option) any later version.
        !             9:  * Please read the file COPYING, README and AUTHORS for more information.
        !            10:  */
        !            11:
        !            12: #include "portab.h"
        !            13:
        !            14: /**
        !            15:  * @file
        !            16:  * snprintf() and vsnprintf() replacement functions
        !            17:  */
        !            18:
        !            19: /*
        !            20:  * snprintf.c: Copyright Patrick Powell 1995
        !            21:  * This code is based on code written by Patrick Powell (papowell@astart.com)
        !            22:  * It may be used for any purpose as long as this notice remains intact
        !            23:  * on all source code distributions
        !            24:  *
        !            25:  * Original: Patrick Powell Tue Apr 11 09:48:21 PDT 1995
        !            26:  * A bombproof version of doprnt (dopr) included.
        !            27:  * Sigh. This sort of thing is always nasty do deal with. Note that
        !            28:  * the version here does not include floating point...
        !            29:  *
        !            30:  * snprintf() is used instead of sprintf() as it does limit checks
        !            31:  * for string length. This covers a nasty loophole.
        !            32:  *
        !            33:  * The other functions are there to prevent NULL pointers from
        !            34:  * causing nast effects.
        !            35:  *
        !            36:  * More Recently:
        !            37:  *  Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
        !            38:  *  This was ugly. It is still ugly. I opted out of floating point
        !            39:  *  numbers, but the formatter understands just about everything
        !            40:  *  from the normal C string format, at least as far as I can tell from
        !            41:  *  the Solaris 2.5 printf(3S) man page.
        !            42:  *
        !            43:  * Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
        !            44:  *  Ok, added some minimal floating point support, which means this
        !            45:  *  probably requires libm on most operating systems. Don't yet
        !            46:  *  support the exponent (e,E) and sigfig (g,G). Also, fmtint()
        !            47:  *  was pretty badly broken, it just wasn't being exercised in ways
        !            48:  *  which showed it, so that's been fixed. Also, formated the code
        !            49:  *  to mutt conventions, and removed dead code left over from the
        !            50:  *  original. Also, there is now a builtin-test, just compile with:
        !            51:  *    gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
        !            52:  *  and run snprintf for results.
        !            53:  *
        !            54:  * Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
        !            55:  *  The PGP code was using unsigned hexadecimal formats.
        !            56:  *  Unfortunately, unsigned formats simply didn't work.
        !            57:  *
        !            58:  * Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
        !            59:  *  The original code assumed that both snprintf() and vsnprintf() were
        !            60:  *  missing. Some systems only have snprintf() but not vsnprintf(), so
        !            61:  *  the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
        !            62:  *
        !            63:  * Andrew Tridgell <tridge@samba.org>, October 1998
        !            64:  *  fixed handling of %.0f
        !            65:  *  added test for HAVE_LONG_DOUBLE
        !            66:  *
        !            67:  * tridge@samba.org, idra@samba.org, April 2001
        !            68:  *  got rid of fcvt code (twas buggy and made testing harder)
        !            69:  *  added C99 semantics
        !            70:  *
        !            71:  * Alexander Barton, <alex@barton.de>, 2002-05-19
        !            72:  *  removed [v]asprintf() and C99 tests: not needed by ngIRCd.
        !            73:  */
        !            74:
        !            75: #ifdef HAVE_STRING_H
        !            76: #include <string.h>
        !            77: #endif
        !            78: #ifdef HAVE_STRINGS_H
        !            79: #include <strings.h>
        !            80: #endif
        !            81: #ifdef HAVE_CTYPE_H
        !            82: #include <ctype.h>
        !            83: #endif
        !            84: #include <sys/types.h>
        !            85: #include <stdarg.h>
        !            86: #ifdef HAVE_STDLIB_H
        !            87: #include <stdlib.h>
        !            88: #endif
        !            89:
        !            90: #if defined(HAVE_SNPRINTF) && defined(HAVE_VSNPRINTF)
        !            91: /* only include stdio.h if we are not re-defining snprintf or vsnprintf */
        !            92: #include <stdio.h>
        !            93: /* make the compiler happy with an empty file */
        !            94: void dummy_snprintf PARAMS(( void ));
        !            95: void dummy_snprintf PARAMS(( void )) { }
        !            96: #else
        !            97:
        !            98: #ifdef HAVE_LONG_DOUBLE
        !            99: #define LDOUBLE long double
        !           100: #else
        !           101: #define LDOUBLE double
        !           102: #endif
        !           103:
        !           104: #ifdef HAVE_LONG_LONG
        !           105: #define LLONG long long
        !           106: #else
        !           107: #define LLONG long
        !           108: #endif
        !           109:
        !           110: static size_t dopr PARAMS((char *buffer, size_t maxlen, const char *format,
        !           111:                           va_list args));
        !           112: static void fmtstr PARAMS((char *buffer, size_t *currlen, size_t maxlen,
        !           113:                           char *value, int flags, int min, int max));
        !           114: static void fmtint PARAMS((char *buffer, size_t *currlen, size_t maxlen,
        !           115:                           long value, int base, int min, int max, int flags));
        !           116: static void fmtfp PARAMS((char *buffer, size_t *currlen, size_t maxlen,
        !           117:                          LDOUBLE fvalue, int min, int max, int flags));
        !           118: static void dopr_outch PARAMS((char *buffer, size_t *currlen, size_t maxlen,
        !           119:                               char c));
        !           120:
        !           121: /*
        !           122:  * dopr(): poor man's version of doprintf
        !           123:  */
        !           124:
        !           125: /* format read states */
        !           126: #define DP_S_DEFAULT 0
        !           127: #define DP_S_FLAGS   1
        !           128: #define DP_S_MIN     2
        !           129: #define DP_S_DOT     3
        !           130: #define DP_S_MAX     4
        !           131: #define DP_S_MOD     5
        !           132: #define DP_S_CONV    6
        !           133: #define DP_S_DONE    7
        !           134:
        !           135: /* format flags - Bits */
        !           136: #define DP_F_MINUS      (1 << 0)
        !           137: #define DP_F_PLUS       (1 << 1)
        !           138: #define DP_F_SPACE      (1 << 2)
        !           139: #define DP_F_NUM       (1 << 3)
        !           140: #define DP_F_ZERO       (1 << 4)
        !           141: #define DP_F_UP         (1 << 5)
        !           142: #define DP_F_UNSIGNED   (1 << 6)
        !           143:
        !           144: /* Conversion Flags */
        !           145: #define DP_C_SHORT   1
        !           146: #define DP_C_LONG    2
        !           147: #define DP_C_LDOUBLE 3
        !           148: #define DP_C_LLONG   4
        !           149:
        !           150: #define char_to_int(p) ((p)- '0')
        !           151: #ifndef MAX
        !           152: #define MAX(p,q) (((p) >= (q)) ? (p) : (q))
        !           153: #endif
        !           154:
        !           155: static size_t
        !           156: dopr(char *buffer, size_t maxlen, const char *format, va_list args)
        !           157: {
        !           158:        char ch;
        !           159:        LLONG value;
        !           160:        LDOUBLE fvalue;
        !           161:        char *strvalue;
        !           162:        int min;
        !           163:        int max;
        !           164:        int state;
        !           165:        int flags;
        !           166:        int cflags;
        !           167:        size_t currlen;
        !           168:
        !           169:        state = DP_S_DEFAULT;
        !           170:        currlen = flags = cflags = min = 0;
        !           171:        max = -1;
        !           172:        ch = *format++;
        !           173:
        !           174:        while (state != DP_S_DONE) {
        !           175:                if (ch == '\0')
        !           176:                        state = DP_S_DONE;
        !           177:
        !           178:                switch(state) {
        !           179:                case DP_S_DEFAULT:
        !           180:                        if (ch == '%')
        !           181:                                state = DP_S_FLAGS;
        !           182:                        else
        !           183:                                dopr_outch (buffer, &currlen, maxlen, ch);
        !           184:                        ch = *format++;
        !           185:                        break;
        !           186:                case DP_S_FLAGS:
        !           187:                        switch (ch) {
        !           188:                        case '-':
        !           189:                                flags |= DP_F_MINUS;
        !           190:                                ch = *format++;
        !           191:                                break;
        !           192:                        case '+':
        !           193:                                flags |= DP_F_PLUS;
        !           194:                                ch = *format++;
        !           195:                                break;
        !           196:                        case ' ':
        !           197:                                flags |= DP_F_SPACE;
        !           198:                                ch = *format++;
        !           199:                                break;
        !           200:                        case '#':
        !           201:                                flags |= DP_F_NUM;
        !           202:                                ch = *format++;
        !           203:                                break;
        !           204:                        case '0':
        !           205:                                flags |= DP_F_ZERO;
        !           206:                                ch = *format++;
        !           207:                                break;
        !           208:                        default:
        !           209:                                state = DP_S_MIN;
        !           210:                                break;
        !           211:                        }
        !           212:                        break;
        !           213:                case DP_S_MIN:
        !           214:                        if (isdigit((unsigned char)ch)) {
        !           215:                                min = 10*min + char_to_int (ch);
        !           216:                                ch = *format++;
        !           217:                        } else if (ch == '*') {
        !           218:                                min = va_arg (args, int);
        !           219:                                ch = *format++;
        !           220:                                state = DP_S_DOT;
        !           221:                        } else {
        !           222:                                state = DP_S_DOT;
        !           223:                        }
        !           224:                        break;
        !           225:                case DP_S_DOT:
        !           226:                        if (ch == '.') {
        !           227:                                state = DP_S_MAX;
        !           228:                                ch = *format++;
        !           229:                        } else {
        !           230:                                state = DP_S_MOD;
        !           231:                        }
        !           232:                        break;
        !           233:                case DP_S_MAX:
        !           234:                        if (isdigit((unsigned char)ch)) {
        !           235:                                if (max < 0)
        !           236:                                        max = 0;
        !           237:                                max = 10*max + char_to_int (ch);
        !           238:                                ch = *format++;
        !           239:                        } else if (ch == '*') {
        !           240:                                max = va_arg (args, int);
        !           241:                                ch = *format++;
        !           242:                                state = DP_S_MOD;
        !           243:                        } else {
        !           244:                                state = DP_S_MOD;
        !           245:                        }
        !           246:                        break;
        !           247:                case DP_S_MOD:
        !           248:                        switch (ch) {
        !           249:                        case 'h':
        !           250:                                cflags = DP_C_SHORT;
        !           251:                                ch = *format++;
        !           252:                                break;
        !           253:                        case 'l':
        !           254:                                cflags = DP_C_LONG;
        !           255:                                ch = *format++;
        !           256:                                if (ch == 'l') {        /* It's a long long */
        !           257:                                        cflags = DP_C_LLONG;
        !           258:                                        ch = *format++;
        !           259:                                }
        !           260:                                break;
        !           261:                        case 'L':
        !           262:                                cflags = DP_C_LDOUBLE;
        !           263:                                ch = *format++;
        !           264:                                break;
        !           265:                        default:
        !           266:                                break;
        !           267:                        }
        !           268:                        state = DP_S_CONV;
        !           269:                        break;
        !           270:                case DP_S_CONV:
        !           271:                        switch (ch) {
        !           272:                        case 'd':
        !           273:                        case 'i':
        !           274:                                if (cflags == DP_C_SHORT)
        !           275:                                        value = va_arg (args, int);
        !           276:                                else if (cflags == DP_C_LONG)
        !           277:                                        value = va_arg (args, long int);
        !           278:                                else if (cflags == DP_C_LLONG)
        !           279:                                        value = va_arg (args, LLONG);
        !           280:                                else
        !           281:                                        value = va_arg (args, int);
        !           282:                                fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
        !           283:                                break;
        !           284:                        case 'o':
        !           285:                                flags |= DP_F_UNSIGNED;
        !           286:                                if (cflags == DP_C_SHORT)
        !           287:                                        value = va_arg (args, unsigned int);
        !           288:                                else if (cflags == DP_C_LONG)
        !           289:                                        value = (long)va_arg (args, unsigned long int);
        !           290:                                else if (cflags == DP_C_LLONG)
        !           291:                                        value = (long)va_arg (args, unsigned LLONG);
        !           292:                                else
        !           293:                                        value = (long)va_arg (args, unsigned int);
        !           294:                                fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
        !           295:                                break;
        !           296:                        case 'u':
        !           297:                                flags |= DP_F_UNSIGNED;
        !           298:                                if (cflags == DP_C_SHORT)
        !           299:                                        value = va_arg (args, unsigned int);
        !           300:                                else if (cflags == DP_C_LONG)
        !           301:                                        value = (long)va_arg (args, unsigned long int);
        !           302:                                else if (cflags == DP_C_LLONG)
        !           303:                                        value = (LLONG)va_arg (args, unsigned LLONG);
        !           304:                                else
        !           305:                                        value = (long)va_arg (args, unsigned int);
        !           306:                                fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
        !           307:                                break;
        !           308:                        case 'X':
        !           309:                                flags |= DP_F_UP;
        !           310:                        case 'x':
        !           311:                                flags |= DP_F_UNSIGNED;
        !           312:                                if (cflags == DP_C_SHORT)
        !           313:                                        value = va_arg (args, unsigned int);
        !           314:                                else if (cflags == DP_C_LONG)
        !           315:                                        value = (long)va_arg (args, unsigned long int);
        !           316:                                else if (cflags == DP_C_LLONG)
        !           317:                                        value = (LLONG)va_arg (args, unsigned LLONG);
        !           318:                                else
        !           319:                                        value = (long)va_arg (args, unsigned int);
        !           320:                                fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
        !           321:                                break;
        !           322:                        case 'f':
        !           323:                                if (cflags == DP_C_LDOUBLE)
        !           324:                                        fvalue = va_arg (args, LDOUBLE);
        !           325:                                else
        !           326:                                        fvalue = va_arg (args, double);
        !           327:                                /* um, floating point? */
        !           328:                                fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
        !           329:                                break;
        !           330:                        case 'E':
        !           331:                                flags |= DP_F_UP;
        !           332:                        case 'e':
        !           333:                                if (cflags == DP_C_LDOUBLE)
        !           334:                                        fvalue = va_arg (args, LDOUBLE);
        !           335:                                else
        !           336:                                        fvalue = va_arg (args, double);
        !           337:                                break;
        !           338:                        case 'G':
        !           339:                                flags |= DP_F_UP;
        !           340:                        case 'g':
        !           341:                                if (cflags == DP_C_LDOUBLE)
        !           342:                                        fvalue = va_arg (args, LDOUBLE);
        !           343:                                else
        !           344:                                        fvalue = va_arg (args, double);
        !           345:                                break;
        !           346:                        case 'c':
        !           347:                                dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
        !           348:                                break;
        !           349:                        case 's':
        !           350:                                strvalue = va_arg (args, char *);
        !           351:                                if (max == -1) {
        !           352:                                        max = strlen(strvalue);
        !           353:                                }
        !           354:                                if (min > 0 && max >= 0 && min > max) max = min;
        !           355:                                fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
        !           356:                                break;
        !           357:                        case 'p':
        !           358:                                strvalue = va_arg (args, void *);
        !           359:                                fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
        !           360:                                break;
        !           361:                        case 'n':
        !           362:                                if (cflags == DP_C_SHORT) {
        !           363:                                        short int *num;
        !           364:                                        num = va_arg (args, short int *);
        !           365:                                        *num = currlen;
        !           366:                                } else if (cflags == DP_C_LONG) {
        !           367:                                        long int *num;
        !           368:                                        num = va_arg (args, long int *);
        !           369:                                        *num = (long int)currlen;
        !           370:                                } else if (cflags == DP_C_LLONG) {
        !           371:                                        LLONG *num;
        !           372:                                        num = va_arg (args, LLONG *);
        !           373:                                        *num = (LLONG)currlen;
        !           374:                                } else {
        !           375:                                        int *num;
        !           376:                                        num = va_arg (args, int *);
        !           377:                                        *num = currlen;
        !           378:                                }
        !           379:                                break;
        !           380:                        case '%':
        !           381:                                dopr_outch (buffer, &currlen, maxlen, ch);
        !           382:                                break;
        !           383:                        case 'w':
        !           384:                                /* not supported yet, treat as next char */
        !           385:                                ch = *format++;
        !           386:                                break;
        !           387:                        default:
        !           388:                                /* Unknown, skip */
        !           389:                                break;
        !           390:                        }
        !           391:                        ch = *format++;
        !           392:                        state = DP_S_DEFAULT;
        !           393:                        flags = cflags = min = 0;
        !           394:                        max = -1;
        !           395:                        break;
        !           396:                case DP_S_DONE:
        !           397:                        break;
        !           398:                default:
        !           399:                        /* hmm? */
        !           400:                        break; /* some picky compilers need this */
        !           401:                }
        !           402:        }
        !           403:        if (maxlen != 0) {
        !           404:                if (currlen < maxlen - 1)
        !           405:                        buffer[currlen] = '\0';
        !           406:                else if (maxlen > 0)
        !           407:                        buffer[maxlen - 1] = '\0';
        !           408:        }
        !           409:
        !           410:        return currlen;
        !           411: }
        !           412:
        !           413: static void
        !           414: fmtstr(char *buffer, size_t *currlen, size_t maxlen, char *value, int flags,
        !           415:        int min, int max)
        !           416: {
        !           417:        int padlen, strln;     /* amount to pad */
        !           418:        int cnt = 0;
        !           419:
        !           420: #ifdef DEBUG_SNPRINTF
        !           421:        printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value);
        !           422: #endif
        !           423:        if (value == 0) {
        !           424:                value = "<NULL>";
        !           425:        }
        !           426:
        !           427:        for (strln = 0; value[strln]; ++strln); /* strlen */
        !           428:        padlen = min - strln;
        !           429:        if (padlen < 0)
        !           430:                padlen = 0;
        !           431:        if (flags & DP_F_MINUS)
        !           432:                padlen = -padlen; /* Left Justify */
        !           433:
        !           434:        while ((padlen > 0) && (cnt < max)) {
        !           435:                dopr_outch (buffer, currlen, maxlen, ' ');
        !           436:                --padlen;
        !           437:                ++cnt;
        !           438:        }
        !           439:        while (*value && (cnt < max)) {
        !           440:                dopr_outch (buffer, currlen, maxlen, *value++);
        !           441:                ++cnt;
        !           442:        }
        !           443:        while ((padlen < 0) && (cnt < max)) {
        !           444:                dopr_outch (buffer, currlen, maxlen, ' ');
        !           445:                ++padlen;
        !           446:                ++cnt;
        !           447:        }
        !           448: }
        !           449:
        !           450: /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
        !           451:
        !           452: static void
        !           453: fmtint(char *buffer, size_t *currlen, size_t maxlen, long value, int base,
        !           454:        int min, int max, int flags)
        !           455: {
        !           456:        int signvalue = 0;
        !           457:        unsigned long uvalue;
        !           458:        char convert[20];
        !           459:        int place = 0;
        !           460:        int spadlen = 0; /* amount to space pad */
        !           461:        int zpadlen = 0; /* amount to zero pad */
        !           462:        int caps = 0;
        !           463:
        !           464:        if (max < 0)
        !           465:                max = 0;
        !           466:
        !           467:        uvalue = value;
        !           468:
        !           469:        if(!(flags & DP_F_UNSIGNED)) {
        !           470:                if( value < 0 ) {
        !           471:                        signvalue = '-';
        !           472:                        uvalue = -value;
        !           473:                } else {
        !           474:                        if (flags & DP_F_PLUS)  /* Do a sign (+/i) */
        !           475:                                signvalue = '+';
        !           476:                        else if (flags & DP_F_SPACE)
        !           477:                                signvalue = ' ';
        !           478:                }
        !           479:        }
        !           480:
        !           481:        if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
        !           482:
        !           483:        do {
        !           484:                convert[place++] =
        !           485:                        (caps? "0123456789ABCDEF":"0123456789abcdef")
        !           486:                        [uvalue % (unsigned)base  ];
        !           487:                uvalue = (uvalue / (unsigned)base );
        !           488:        } while(uvalue && (place < 20));
        !           489:        if (place == 20) place--;
        !           490:        convert[place] = 0;
        !           491:
        !           492:        zpadlen = max - place;
        !           493:        spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
        !           494:        if (zpadlen < 0) zpadlen = 0;
        !           495:        if (spadlen < 0) spadlen = 0;
        !           496:        if (flags & DP_F_ZERO) {
        !           497:                zpadlen = MAX(zpadlen, spadlen);
        !           498:                spadlen = 0;
        !           499:        }
        !           500:        if (flags & DP_F_MINUS)
        !           501:                spadlen = -spadlen; /* Left Justifty */
        !           502:
        !           503: #ifdef DEBUG_SNPRINTF
        !           504:        printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
        !           505:               zpadlen, spadlen, min, max, place);
        !           506: #endif
        !           507:
        !           508:        /* Spaces */
        !           509:        while (spadlen > 0) {
        !           510:                dopr_outch (buffer, currlen, maxlen, ' ');
        !           511:                --spadlen;
        !           512:        }
        !           513:
        !           514:        /* Sign */
        !           515:        if (signvalue)
        !           516:                dopr_outch (buffer, currlen, maxlen, signvalue);
        !           517:
        !           518:        /* Zeros */
        !           519:        if (zpadlen > 0) {
        !           520:                while (zpadlen > 0) {
        !           521:                        dopr_outch (buffer, currlen, maxlen, '0');
        !           522:                        --zpadlen;
        !           523:                }
        !           524:        }
        !           525:
        !           526:        /* Digits */
        !           527:        while (place > 0)
        !           528:                dopr_outch (buffer, currlen, maxlen, convert[--place]);
        !           529:
        !           530:        /* Left Justified spaces */
        !           531:        while (spadlen < 0) {
        !           532:                dopr_outch (buffer, currlen, maxlen, ' ');
        !           533:                ++spadlen;
        !           534:        }
        !           535: }
        !           536:
        !           537: static LDOUBLE
        !           538: abs_val(LDOUBLE value)
        !           539: {
        !           540:        LDOUBLE result = value;
        !           541:
        !           542:        if (value < 0)
        !           543:                result = -value;
        !           544:
        !           545:        return result;
        !           546: }
        !           547:
        !           548: static LDOUBLE
        !           549: POW10(int exp)
        !           550: {
        !           551:        LDOUBLE result = 1;
        !           552:
        !           553:        while (exp) {
        !           554:                result *= 10;
        !           555:                exp--;
        !           556:        }
        !           557:
        !           558:        return result;
        !           559: }
        !           560:
        !           561: static LLONG
        !           562: ROUND(LDOUBLE value)
        !           563: {
        !           564:        LLONG intpart;
        !           565:
        !           566:        intpart = (LLONG)value;
        !           567:        value = value - intpart;
        !           568:        if (value >= 0.5) intpart++;
        !           569:
        !           570:        return intpart;
        !           571: }
        !           572:
        !           573: /* a replacement for modf that doesn't need the math library. Should
        !           574:    be portable, but slow */
        !           575: static double
        !           576: my_modf(double x0, double *iptr)
        !           577: {
        !           578:        int i;
        !           579:        long l;
        !           580:        double x = x0;
        !           581:        double f = 1.0;
        !           582:
        !           583:        for (i=0;i<100;i++) {
        !           584:                l = (long)x;
        !           585:                if (l <= (x+1) && l >= (x-1)) break;
        !           586:                x *= 0.1;
        !           587:                f *= 10.0;
        !           588:        }
        !           589:
        !           590:        if (i == 100) {
        !           591:                /* yikes! the number is beyond what we can handle. What do we do? */
        !           592:                (*iptr) = 0;
        !           593:                return 0;
        !           594:        }
        !           595:
        !           596:        if (i != 0) {
        !           597:                double i2;
        !           598:                double ret;
        !           599:
        !           600:                ret = my_modf(x0-l*f, &i2);
        !           601:                (*iptr) = l*f + i2;
        !           602:                return ret;
        !           603:        }
        !           604:
        !           605:        (*iptr) = l;
        !           606:        return x - (*iptr);
        !           607: }
        !           608:
        !           609:
        !           610: static void
        !           611: fmtfp (char *buffer, size_t *currlen, size_t maxlen, LDOUBLE fvalue,
        !           612:        int min, int max, int flags)
        !           613: {
        !           614:        int signvalue = 0;
        !           615:        double ufvalue;
        !           616:        char iconvert[311];
        !           617:        char fconvert[311];
        !           618:        int iplace = 0;
        !           619:        int fplace = 0;
        !           620:        int padlen = 0; /* amount to pad */
        !           621:        int zpadlen = 0;
        !           622:        int caps = 0;
        !           623:        int index;
        !           624:        double intpart;
        !           625:        double fracpart;
        !           626:        double temp;
        !           627:
        !           628:        /*
        !           629:         * AIX manpage says the default is 0, but Solaris says the default
        !           630:         * is 6, and sprintf on AIX defaults to 6
        !           631:         */
        !           632:        if (max < 0)
        !           633:                max = 6;
        !           634:
        !           635:        ufvalue = abs_val (fvalue);
        !           636:
        !           637:        if (fvalue < 0) {
        !           638:                signvalue = '-';
        !           639:        } else {
        !           640:                if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
        !           641:                        signvalue = '+';
        !           642:                } else {
        !           643:                        if (flags & DP_F_SPACE)
        !           644:                                signvalue = ' ';
        !           645:                }
        !           646:        }
        !           647:
        !           648:        /*
        !           649:         * Sorry, we only support 16 digits past the decimal because of our
        !           650:         * conversion method
        !           651:         */
        !           652:        if (max > 16)
        !           653:                max = 16;
        !           654:
        !           655:        /* We "cheat" by converting the fractional part to integer by
        !           656:         * multiplying by a factor of 10
        !           657:         */
        !           658:
        !           659:        temp = ufvalue;
        !           660:        my_modf(temp, &intpart);
        !           661:
        !           662:        fracpart = ROUND((POW10(max)) * (ufvalue - intpart));
        !           663:
        !           664:        if (fracpart >= POW10(max)) {
        !           665:                intpart++;
        !           666:                fracpart -= POW10(max);
        !           667:        }
        !           668:
        !           669:
        !           670:        /* Convert integer part */
        !           671:        do {
        !           672:                temp = intpart;
        !           673:                my_modf(intpart*0.1, &intpart);
        !           674:                temp = temp*0.1;
        !           675:                index = (int) ((temp -intpart +0.05)* 10.0);
        !           676:                /* index = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */
        !           677:                /* printf ("%llf, %f, %x\n", temp, intpart, index); */
        !           678:                iconvert[iplace++] =
        !           679:                        (caps? "0123456789ABCDEF":"0123456789abcdef")[index];
        !           680:        } while (intpart && (iplace < 311));
        !           681:        if (iplace == 311) iplace--;
        !           682:        iconvert[iplace] = 0;
        !           683:
        !           684:        /* Convert fractional part */
        !           685:        if (fracpart)
        !           686:        {
        !           687:                do {
        !           688:                        temp = fracpart;
        !           689:                        my_modf(fracpart*0.1, &fracpart);
        !           690:                        temp = temp*0.1;
        !           691:                        index = (int) ((temp -fracpart +0.05)* 10.0);
        !           692:                        /* index = (int) ((((temp/10) -fracpart) +0.05) *10); */
        !           693:                        /* printf ("%lf, %lf, %ld\n", temp, fracpart, index); */
        !           694:                        fconvert[fplace++] =
        !           695:                        (caps? "0123456789ABCDEF":"0123456789abcdef")[index];
        !           696:                } while(fracpart && (fplace < 311));
        !           697:                if (fplace == 311) fplace--;
        !           698:        }
        !           699:        fconvert[fplace] = 0;
        !           700:
        !           701:        /* -1 for decimal point, another -1 if we are printing a sign */
        !           702:        padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
        !           703:        zpadlen = max - fplace;
        !           704:        if (zpadlen < 0) zpadlen = 0;
        !           705:        if (padlen < 0)
        !           706:                padlen = 0;
        !           707:        if (flags & DP_F_MINUS)
        !           708:                padlen = -padlen; /* Left Justifty */
        !           709:
        !           710:        if ((flags & DP_F_ZERO) && (padlen > 0)) {
        !           711:                if (signvalue) {
        !           712:                        dopr_outch (buffer, currlen, maxlen, signvalue);
        !           713:                        --padlen;
        !           714:                        signvalue = 0;
        !           715:                }
        !           716:                while (padlen > 0) {
        !           717:                        dopr_outch (buffer, currlen, maxlen, '0');
        !           718:                        --padlen;
        !           719:                }
        !           720:        }
        !           721:        while (padlen > 0) {
        !           722:                dopr_outch (buffer, currlen, maxlen, ' ');
        !           723:                --padlen;
        !           724:        }
        !           725:        if (signvalue)
        !           726:                dopr_outch (buffer, currlen, maxlen, signvalue);
        !           727:
        !           728:        while (iplace > 0)
        !           729:                dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
        !           730:
        !           731: #ifdef DEBUG_SNPRINTF
        !           732:        printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
        !           733: #endif
        !           734:
        !           735:        /*
        !           736:         * Decimal point.  This should probably use locale to find the correct
        !           737:         * char to print out.
        !           738:         */
        !           739:        if (max > 0) {
        !           740:                dopr_outch (buffer, currlen, maxlen, '.');
        !           741:
        !           742:                while (fplace > 0)
        !           743:                        dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
        !           744:        }
        !           745:
        !           746:        while (zpadlen > 0) {
        !           747:                dopr_outch (buffer, currlen, maxlen, '0');
        !           748:                --zpadlen;
        !           749:        }
        !           750:
        !           751:        while (padlen < 0) {
        !           752:                dopr_outch (buffer, currlen, maxlen, ' ');
        !           753:                ++padlen;
        !           754:        }
        !           755: }
        !           756:
        !           757: static void
        !           758: dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
        !           759: {
        !           760:        if (*currlen < maxlen) {
        !           761:                buffer[(*currlen)] = c;
        !           762:        }
        !           763:        (*currlen)++;
        !           764: }
        !           765:
        !           766: #if !defined(HAVE_VSNPRINTF)
        !           767: int
        !           768: vsnprintf (char *str, size_t count, const char *fmt, va_list args)
        !           769: {
        !           770:        return dopr(str, count, fmt, args);
        !           771: }
        !           772: #endif
        !           773:
        !           774: #if !defined(HAVE_SNPRINTF)
        !           775: #ifdef PROTOTYPES
        !           776: int
        !           777: snprintf(char *str, size_t count, const char *fmt, ...)
        !           778: #else
        !           779: int
        !           780: snprintf(str, count, fmt, va_alist)
        !           781: char *str;
        !           782: size_t count;
        !           783: const char *fmt;
        !           784: va_dcl
        !           785: #endif
        !           786: {
        !           787:        size_t ret;
        !           788:        va_list ap;
        !           789:
        !           790:        va_start(ap, fmt);
        !           791:        ret = vsnprintf(str, count, fmt, ap);
        !           792:        va_end(ap);
        !           793:        return ret;
        !           794: }
        !           795: #endif
        !           796:
        !           797: #endif
        !           798:
        !           799: /* -eof- */

CVSweb