Annotation of embedaddon/rsync/lib/snprintf.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * NOTE: If you change this file, please merge it into rsync, samba, etc.
        !             3:  */
        !             4: 
        !             5: /*
        !             6:  * Copyright Patrick Powell 1995
        !             7:  * This code is based on code written by Patrick Powell (papowell@astart.com)
        !             8:  * It may be used for any purpose as long as this notice remains intact
        !             9:  * on all source code distributions
        !            10:  */
        !            11: 
        !            12: /**************************************************************
        !            13:  * Original:
        !            14:  * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
        !            15:  * A bombproof version of doprnt (dopr) included.
        !            16:  * Sigh.  This sort of thing is always nasty do deal with.  Note that
        !            17:  * the version here does not include floating point...
        !            18:  *
        !            19:  * snprintf() is used instead of sprintf() as it does limit checks
        !            20:  * for string length.  This covers a nasty loophole.
        !            21:  *
        !            22:  * The other functions are there to prevent NULL pointers from
        !            23:  * causing nast effects.
        !            24:  *
        !            25:  * More Recently:
        !            26:  *  Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
        !            27:  *  This was ugly.  It is still ugly.  I opted out of floating point
        !            28:  *  numbers, but the formatter understands just about everything
        !            29:  *  from the normal C string format, at least as far as I can tell from
        !            30:  *  the Solaris 2.5 printf(3S) man page.
        !            31:  *
        !            32:  *  Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
        !            33:  *    Ok, added some minimal floating point support, which means this
        !            34:  *    probably requires libm on most operating systems.  Don't yet
        !            35:  *    support the exponent (e,E) and sigfig (g,G).  Also, fmtint()
        !            36:  *    was pretty badly broken, it just wasn't being exercised in ways
        !            37:  *    which showed it, so that's been fixed.  Also, formated the code
        !            38:  *    to mutt conventions, and removed dead code left over from the
        !            39:  *    original.  Also, there is now a builtin-test, just compile with:
        !            40:  *           gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
        !            41:  *    and run snprintf for results.
        !            42:  * 
        !            43:  *  Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
        !            44:  *    The PGP code was using unsigned hexadecimal formats. 
        !            45:  *    Unfortunately, unsigned formats simply didn't work.
        !            46:  *
        !            47:  *  Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
        !            48:  *    The original code assumed that both snprintf() and vsnprintf() were
        !            49:  *    missing.  Some systems only have snprintf() but not vsnprintf(), so
        !            50:  *    the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
        !            51:  *
        !            52:  *  Andrew Tridgell (tridge@samba.org) Oct 1998
        !            53:  *    fixed handling of %.0f
        !            54:  *    added test for HAVE_LONG_DOUBLE
        !            55:  *
        !            56:  * tridge@samba.org, idra@samba.org, April 2001
        !            57:  *    got rid of fcvt code (twas buggy and made testing harder)
        !            58:  *    added C99 semantics
        !            59:  *
        !            60:  * date: 2002/12/19 19:56:31;  author: herb;  state: Exp;  lines: +2 -0
        !            61:  * actually print args for %g and %e
        !            62:  * 
        !            63:  * date: 2002/06/03 13:37:52;  author: jmcd;  state: Exp;  lines: +8 -0
        !            64:  * Since includes.h isn't included here, VA_COPY has to be defined here.  I don't
        !            65:  * see any include file that is guaranteed to be here, so I'm defining it
        !            66:  * locally.  Fixes AIX and Solaris builds.
        !            67:  * 
        !            68:  * date: 2002/06/03 03:07:24;  author: tridge;  state: Exp;  lines: +5 -13
        !            69:  * put the ifdef for HAVE_VA_COPY in one place rather than in lots of
        !            70:  * functions
        !            71:  * 
        !            72:  * date: 2002/05/17 14:51:22;  author: jmcd;  state: Exp;  lines: +21 -4
        !            73:  * Fix usage of va_list passed as an arg.  Use __va_copy before using it
        !            74:  * when it exists.
        !            75:  * 
        !            76:  * date: 2002/04/16 22:38:04;  author: idra;  state: Exp;  lines: +20 -14
        !            77:  * Fix incorrect zpadlen handling in fmtfp.
        !            78:  * Thanks to Ollie Oldham <ollie.oldham@metro-optix.com> for spotting it.
        !            79:  * few mods to make it easier to compile the tests.
        !            80:  * addedd the "Ollie" test to the floating point ones.
        !            81:  *
        !            82:  * Martin Pool (mbp@samba.org) April 2003
        !            83:  *    Remove NO_CONFIG_H so that the test case can be built within a source
        !            84:  *    tree with less trouble.
        !            85:  *    Remove unnecessary SAFE_FREE() definition.
        !            86:  *
        !            87:  * Martin Pool (mbp@samba.org) May 2003
        !            88:  *    Put in a prototype for dummy_snprintf() to quiet compiler warnings.
        !            89:  *
        !            90:  *    Move #endif to make sure VA_COPY, LDOUBLE, etc are defined even
        !            91:  *    if the C library has some snprintf functions already.
        !            92:  **************************************************************/
        !            93: 
        !            94: #ifndef NO_CONFIG_H
        !            95: #include "config.h"
        !            96: #else
        !            97: #define NULL 0
        !            98: #endif 
        !            99: 
        !           100: #ifdef TEST_SNPRINTF /* need math library headers for testing */
        !           101: 
        !           102: /* In test mode, we pretend that this system doesn't have any snprintf
        !           103:  * functions, regardless of what config.h says. */
        !           104: #  undef HAVE_SNPRINTF
        !           105: #  undef HAVE_VSNPRINTF
        !           106: #  undef HAVE_C99_VSNPRINTF
        !           107: #  undef HAVE_ASPRINTF
        !           108: #  undef HAVE_VASPRINTF
        !           109: #  include <math.h>
        !           110: #endif /* TEST_SNPRINTF */
        !           111: 
        !           112: #ifdef HAVE_STRING_H
        !           113: #include <string.h>
        !           114: #endif
        !           115: 
        !           116: #ifdef HAVE_STRINGS_H
        !           117: #include <strings.h>
        !           118: #endif
        !           119: #ifdef HAVE_CTYPE_H
        !           120: #include <ctype.h>
        !           121: #endif
        !           122: #include <sys/types.h>
        !           123: #include <stdarg.h>
        !           124: #ifdef HAVE_STDLIB_H
        !           125: #include <stdlib.h>
        !           126: #endif
        !           127: 
        !           128: #if defined(HAVE_SNPRINTF) && defined(HAVE_VSNPRINTF) && defined(HAVE_C99_VSNPRINTF)
        !           129: /* only include stdio.h if we are not re-defining snprintf or vsnprintf */
        !           130: #include <stdio.h>
        !           131:  /* make the compiler happy with an empty file */
        !           132:  void dummy_snprintf(void);
        !           133:  void dummy_snprintf(void) {} 
        !           134: #endif /* HAVE_SNPRINTF, etc */
        !           135: 
        !           136: #ifdef HAVE_LONG_DOUBLE
        !           137: #define LDOUBLE long double
        !           138: #else
        !           139: #define LDOUBLE double
        !           140: #endif
        !           141: 
        !           142: #if SIZEOF_LONG_LONG
        !           143: #define LLONG long long
        !           144: #else
        !           145: #define LLONG long
        !           146: #endif
        !           147: 
        !           148: #ifndef VA_COPY
        !           149: #if defined HAVE_VA_COPY || defined va_copy
        !           150: #define VA_COPY(dest, src) va_copy(dest, src)
        !           151: #else
        !           152: #ifdef HAVE___VA_COPY
        !           153: #define VA_COPY(dest, src) __va_copy(dest, src)
        !           154: #else
        !           155: #define VA_COPY(dest, src) (dest) = (src)
        !           156: #endif
        !           157: #endif
        !           158: 
        !           159: /*
        !           160:  * dopr(): poor man's version of doprintf
        !           161:  */
        !           162: 
        !           163: /* format read states */
        !           164: #define DP_S_DEFAULT 0
        !           165: #define DP_S_FLAGS   1
        !           166: #define DP_S_MIN     2
        !           167: #define DP_S_DOT     3
        !           168: #define DP_S_MAX     4
        !           169: #define DP_S_MOD     5
        !           170: #define DP_S_CONV    6
        !           171: #define DP_S_DONE    7
        !           172: 
        !           173: /* format flags - Bits */
        !           174: #define DP_F_MINUS     (1 << 0)
        !           175: #define DP_F_PLUS      (1 << 1)
        !           176: #define DP_F_SPACE     (1 << 2)
        !           177: #define DP_F_NUM       (1 << 3)
        !           178: #define DP_F_ZERO      (1 << 4)
        !           179: #define DP_F_UP        (1 << 5)
        !           180: #define DP_F_UNSIGNED  (1 << 6)
        !           181: 
        !           182: /* Conversion Flags */
        !           183: #define DP_C_SHORT   1
        !           184: #define DP_C_LONG    2
        !           185: #define DP_C_LDOUBLE 3
        !           186: #define DP_C_LLONG   4
        !           187: 
        !           188: #define char_to_int(p) ((p)- '0')
        !           189: #ifndef MAX
        !           190: #define MAX(p,q) (((p) >= (q)) ? (p) : (q))
        !           191: #endif
        !           192: 
        !           193: /* yes this really must be a ||. Don't muck with this (tridge) */
        !           194: #if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
        !           195: 
        !           196: static size_t dopr(char *buffer, size_t maxlen, const char *format, 
        !           197:                   va_list args_in);
        !           198: static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
        !           199:                    char *value, int flags, int min, int max);
        !           200: static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
        !           201:                    long value, int base, int min, int max, int flags);
        !           202: static void fmtfp(char *buffer, size_t *currlen, size_t maxlen,
        !           203:                   LDOUBLE fvalue, int min, int max, int flags);
        !           204: static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
        !           205: 
        !           206: static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args_in)
        !           207: {
        !           208:        char ch;
        !           209:        LLONG value;
        !           210:        LDOUBLE fvalue;
        !           211:        char *strvalue;
        !           212:        int min;
        !           213:        int max;
        !           214:        int state;
        !           215:        int flags;
        !           216:        int cflags;
        !           217:        size_t currlen;
        !           218:        va_list args;
        !           219: 
        !           220:        VA_COPY(args, args_in);
        !           221:        
        !           222:        state = DP_S_DEFAULT;
        !           223:        currlen = flags = cflags = min = 0;
        !           224:        max = -1;
        !           225:        ch = *format++;
        !           226:        
        !           227:        while (state != DP_S_DONE) {
        !           228:                if (ch == '\0') 
        !           229:                        state = DP_S_DONE;
        !           230: 
        !           231:                switch(state) {
        !           232:                case DP_S_DEFAULT:
        !           233:                        if (ch == '%') 
        !           234:                                state = DP_S_FLAGS;
        !           235:                        else 
        !           236:                                dopr_outch (buffer, &currlen, maxlen, ch);
        !           237:                        ch = *format++;
        !           238:                        break;
        !           239:                case DP_S_FLAGS:
        !           240:                        switch (ch) {
        !           241:                        case '-':
        !           242:                                flags |= DP_F_MINUS;
        !           243:                                ch = *format++;
        !           244:                                break;
        !           245:                        case '+':
        !           246:                                flags |= DP_F_PLUS;
        !           247:                                ch = *format++;
        !           248:                                break;
        !           249:                        case ' ':
        !           250:                                flags |= DP_F_SPACE;
        !           251:                                ch = *format++;
        !           252:                                break;
        !           253:                        case '#':
        !           254:                                flags |= DP_F_NUM;
        !           255:                                ch = *format++;
        !           256:                                break;
        !           257:                        case '0':
        !           258:                                flags |= DP_F_ZERO;
        !           259:                                ch = *format++;
        !           260:                                break;
        !           261:                        default:
        !           262:                                state = DP_S_MIN;
        !           263:                                break;
        !           264:                        }
        !           265:                        break;
        !           266:                case DP_S_MIN:
        !           267:                        if (isdigit((unsigned char)ch)) {
        !           268:                                min = 10*min + char_to_int (ch);
        !           269:                                ch = *format++;
        !           270:                        } else if (ch == '*') {
        !           271:                                min = va_arg (args, int);
        !           272:                                ch = *format++;
        !           273:                                state = DP_S_DOT;
        !           274:                        } else {
        !           275:                                state = DP_S_DOT;
        !           276:                        }
        !           277:                        break;
        !           278:                case DP_S_DOT:
        !           279:                        if (ch == '.') {
        !           280:                                state = DP_S_MAX;
        !           281:                                ch = *format++;
        !           282:                        } else { 
        !           283:                                state = DP_S_MOD;
        !           284:                        }
        !           285:                        break;
        !           286:                case DP_S_MAX:
        !           287:                        if (isdigit((unsigned char)ch)) {
        !           288:                                if (max < 0)
        !           289:                                        max = 0;
        !           290:                                max = 10*max + char_to_int (ch);
        !           291:                                ch = *format++;
        !           292:                        } else if (ch == '*') {
        !           293:                                max = va_arg (args, int);
        !           294:                                ch = *format++;
        !           295:                                state = DP_S_MOD;
        !           296:                        } else {
        !           297:                                state = DP_S_MOD;
        !           298:                        }
        !           299:                        break;
        !           300:                case DP_S_MOD:
        !           301:                        switch (ch) {
        !           302:                        case 'h':
        !           303:                                cflags = DP_C_SHORT;
        !           304:                                ch = *format++;
        !           305:                                break;
        !           306:                        case 'l':
        !           307:                                cflags = DP_C_LONG;
        !           308:                                ch = *format++;
        !           309:                                if (ch == 'l') {        /* It's a long long */
        !           310:                                        cflags = DP_C_LLONG;
        !           311:                                        ch = *format++;
        !           312:                                }
        !           313:                                break;
        !           314:                        case 'L':
        !           315:                                cflags = DP_C_LDOUBLE;
        !           316:                                ch = *format++;
        !           317:                                break;
        !           318:                        default:
        !           319:                                break;
        !           320:                        }
        !           321:                        state = DP_S_CONV;
        !           322:                        break;
        !           323:                case DP_S_CONV:
        !           324:                        switch (ch) {
        !           325:                        case 'd':
        !           326:                        case 'i':
        !           327:                                if (cflags == DP_C_SHORT) 
        !           328:                                        value = va_arg (args, int);
        !           329:                                else if (cflags == DP_C_LONG)
        !           330:                                        value = va_arg (args, long int);
        !           331:                                else if (cflags == DP_C_LLONG)
        !           332:                                        value = va_arg (args, LLONG);
        !           333:                                else
        !           334:                                        value = va_arg (args, int);
        !           335:                                fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
        !           336:                                break;
        !           337:                        case 'o':
        !           338:                                flags |= DP_F_UNSIGNED;
        !           339:                                if (cflags == DP_C_SHORT)
        !           340:                                        value = va_arg (args, unsigned int);
        !           341:                                else if (cflags == DP_C_LONG)
        !           342:                                        value = (long)va_arg (args, unsigned long int);
        !           343:                                else if (cflags == DP_C_LLONG)
        !           344:                                        value = (long)va_arg (args, unsigned LLONG);
        !           345:                                else
        !           346:                                        value = (long)va_arg (args, unsigned int);
        !           347:                                fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
        !           348:                                break;
        !           349:                        case 'u':
        !           350:                                flags |= DP_F_UNSIGNED;
        !           351:                                if (cflags == DP_C_SHORT)
        !           352:                                        value = va_arg (args, unsigned int);
        !           353:                                else if (cflags == DP_C_LONG)
        !           354:                                        value = (long)va_arg (args, unsigned long int);
        !           355:                                else if (cflags == DP_C_LLONG)
        !           356:                                        value = (LLONG)va_arg (args, unsigned LLONG);
        !           357:                                else
        !           358:                                        value = (long)va_arg (args, unsigned int);
        !           359:                                fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
        !           360:                                break;
        !           361:                        case 'X':
        !           362:                                flags |= DP_F_UP;
        !           363:                        case 'x':
        !           364:                                flags |= DP_F_UNSIGNED;
        !           365:                                if (cflags == DP_C_SHORT)
        !           366:                                        value = va_arg (args, unsigned int);
        !           367:                                else if (cflags == DP_C_LONG)
        !           368:                                        value = (long)va_arg (args, unsigned long int);
        !           369:                                else if (cflags == DP_C_LLONG)
        !           370:                                        value = (LLONG)va_arg (args, unsigned LLONG);
        !           371:                                else
        !           372:                                        value = (long)va_arg (args, unsigned int);
        !           373:                                fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
        !           374:                                break;
        !           375:                        case 'f':
        !           376:                                if (cflags == DP_C_LDOUBLE)
        !           377:                                        fvalue = va_arg (args, LDOUBLE);
        !           378:                                else
        !           379:                                        fvalue = va_arg (args, double);
        !           380:                                /* um, floating point? */
        !           381:                                fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
        !           382:                                break;
        !           383:                        case 'E':
        !           384:                                flags |= DP_F_UP;
        !           385:                        case 'e':
        !           386:                                if (cflags == DP_C_LDOUBLE)
        !           387:                                        fvalue = va_arg (args, LDOUBLE);
        !           388:                                else
        !           389:                                        fvalue = va_arg (args, double);
        !           390:                                fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
        !           391:                                break;
        !           392:                        case 'G':
        !           393:                                flags |= DP_F_UP;
        !           394:                        case 'g':
        !           395:                                if (cflags == DP_C_LDOUBLE)
        !           396:                                        fvalue = va_arg (args, LDOUBLE);
        !           397:                                else
        !           398:                                        fvalue = va_arg (args, double);
        !           399:                                fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
        !           400:                                break;
        !           401:                        case 'c':
        !           402:                                dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
        !           403:                                break;
        !           404:                        case 's':
        !           405:                                strvalue = va_arg (args, char *);
        !           406:                                if (!strvalue) strvalue = "(NULL)";
        !           407:                                if (max == -1) {
        !           408:                                        max = strlen(strvalue);
        !           409:                                }
        !           410:                                if (min > 0 && max >= 0 && min > max) max = min;
        !           411:                                fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
        !           412:                                break;
        !           413:                        case 'p':
        !           414:                                strvalue = va_arg (args, void *);
        !           415:                                fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
        !           416:                                break;
        !           417:                        case 'n':
        !           418:                                if (cflags == DP_C_SHORT) {
        !           419:                                        short int *num;
        !           420:                                        num = va_arg (args, short int *);
        !           421:                                        *num = currlen;
        !           422:                                } else if (cflags == DP_C_LONG) {
        !           423:                                        long int *num;
        !           424:                                        num = va_arg (args, long int *);
        !           425:                                        *num = (long int)currlen;
        !           426:                                } else if (cflags == DP_C_LLONG) {
        !           427:                                        LLONG *num;
        !           428:                                        num = va_arg (args, LLONG *);
        !           429:                                        *num = (LLONG)currlen;
        !           430:                                } else {
        !           431:                                        int *num;
        !           432:                                        num = va_arg (args, int *);
        !           433:                                        *num = currlen;
        !           434:                                }
        !           435:                                break;
        !           436:                        case '%':
        !           437:                                dopr_outch (buffer, &currlen, maxlen, ch);
        !           438:                                break;
        !           439:                        case 'w':
        !           440:                                /* not supported yet, treat as next char */
        !           441:                                ch = *format++;
        !           442:                                break;
        !           443:                        default:
        !           444:                                /* Unknown, skip */
        !           445:                                break;
        !           446:                        }
        !           447:                        ch = *format++;
        !           448:                        state = DP_S_DEFAULT;
        !           449:                        flags = cflags = min = 0;
        !           450:                        max = -1;
        !           451:                        break;
        !           452:                case DP_S_DONE:
        !           453:                        break;
        !           454:                default:
        !           455:                        /* hmm? */
        !           456:                        break; /* some picky compilers need this */
        !           457:                }
        !           458:        }
        !           459:        if (maxlen != 0) {
        !           460:                if (currlen < maxlen - 1) 
        !           461:                        buffer[currlen] = '\0';
        !           462:                else if (maxlen > 0) 
        !           463:                        buffer[maxlen - 1] = '\0';
        !           464:        }
        !           465:        
        !           466:        return currlen;
        !           467: }
        !           468: 
        !           469: static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
        !           470:                    char *value, int flags, int min, int max)
        !           471: {
        !           472:        int padlen, strln;     /* amount to pad */
        !           473:        int cnt = 0;
        !           474: 
        !           475: #ifdef DEBUG_SNPRINTF
        !           476:        printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value);
        !           477: #endif
        !           478:        if (value == 0) {
        !           479:                value = "<NULL>";
        !           480:        }
        !           481: 
        !           482:        for (strln = 0; value[strln]; ++strln); /* strlen */
        !           483:        padlen = min - strln;
        !           484:        if (padlen < 0) 
        !           485:                padlen = 0;
        !           486:        if (flags & DP_F_MINUS) 
        !           487:                padlen = -padlen; /* Left Justify */
        !           488:        
        !           489:        while ((padlen > 0) && (cnt < max)) {
        !           490:                dopr_outch (buffer, currlen, maxlen, ' ');
        !           491:                --padlen;
        !           492:                ++cnt;
        !           493:        }
        !           494:        while (*value && (cnt < max)) {
        !           495:                dopr_outch (buffer, currlen, maxlen, *value++);
        !           496:                ++cnt;
        !           497:        }
        !           498:        while ((padlen < 0) && (cnt < max)) {
        !           499:                dopr_outch (buffer, currlen, maxlen, ' ');
        !           500:                ++padlen;
        !           501:                ++cnt;
        !           502:        }
        !           503: }
        !           504: 
        !           505: /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
        !           506: 
        !           507: static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
        !           508:                    long value, int base, int min, int max, int flags)
        !           509: {
        !           510:        int signvalue = 0;
        !           511:        unsigned long uvalue;
        !           512:        char convert[20];
        !           513:        int place = 0;
        !           514:        int spadlen = 0; /* amount to space pad */
        !           515:        int zpadlen = 0; /* amount to zero pad */
        !           516:        int caps = 0;
        !           517:        
        !           518:        if (max < 0)
        !           519:                max = 0;
        !           520:        
        !           521:        uvalue = value;
        !           522:        
        !           523:        if(!(flags & DP_F_UNSIGNED)) {
        !           524:                if( value < 0 ) {
        !           525:                        signvalue = '-';
        !           526:                        uvalue = -value;
        !           527:                } else {
        !           528:                        if (flags & DP_F_PLUS)  /* Do a sign (+/i) */
        !           529:                                signvalue = '+';
        !           530:                        else if (flags & DP_F_SPACE)
        !           531:                                signvalue = ' ';
        !           532:                }
        !           533:        }
        !           534:   
        !           535:        if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
        !           536: 
        !           537:        do {
        !           538:                convert[place++] =
        !           539:                        (caps? "0123456789ABCDEF":"0123456789abcdef")
        !           540:                        [uvalue % (unsigned)base  ];
        !           541:                uvalue = (uvalue / (unsigned)base );
        !           542:        } while(uvalue && (place < 20));
        !           543:        if (place == 20) place--;
        !           544:        convert[place] = 0;
        !           545: 
        !           546:        zpadlen = max - place;
        !           547:        spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
        !           548:        if (zpadlen < 0) zpadlen = 0;
        !           549:        if (spadlen < 0) spadlen = 0;
        !           550:        if (flags & DP_F_ZERO) {
        !           551:                zpadlen = MAX(zpadlen, spadlen);
        !           552:                spadlen = 0;
        !           553:        }
        !           554:        if (flags & DP_F_MINUS) 
        !           555:                spadlen = -spadlen; /* Left Justifty */
        !           556: 
        !           557: #ifdef DEBUG_SNPRINTF
        !           558:        printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
        !           559:               zpadlen, spadlen, min, max, place);
        !           560: #endif
        !           561: 
        !           562:        /* Spaces */
        !           563:        while (spadlen > 0) {
        !           564:                dopr_outch (buffer, currlen, maxlen, ' ');
        !           565:                --spadlen;
        !           566:        }
        !           567: 
        !           568:        /* Sign */
        !           569:        if (signvalue) 
        !           570:                dopr_outch (buffer, currlen, maxlen, signvalue);
        !           571: 
        !           572:        /* Zeros */
        !           573:        if (zpadlen > 0) {
        !           574:                while (zpadlen > 0) {
        !           575:                        dopr_outch (buffer, currlen, maxlen, '0');
        !           576:                        --zpadlen;
        !           577:                }
        !           578:        }
        !           579: 
        !           580:        /* Digits */
        !           581:        while (place > 0) 
        !           582:                dopr_outch (buffer, currlen, maxlen, convert[--place]);
        !           583:   
        !           584:        /* Left Justified spaces */
        !           585:        while (spadlen < 0) {
        !           586:                dopr_outch (buffer, currlen, maxlen, ' ');
        !           587:                ++spadlen;
        !           588:        }
        !           589: }
        !           590: 
        !           591: static LDOUBLE abs_val(LDOUBLE value)
        !           592: {
        !           593:        LDOUBLE result = value;
        !           594: 
        !           595:        if (value < 0)
        !           596:                result = -value;
        !           597:        
        !           598:        return result;
        !           599: }
        !           600: 
        !           601: static LDOUBLE POW10(int exp)
        !           602: {
        !           603:        LDOUBLE result = 1;
        !           604:        
        !           605:        while (exp) {
        !           606:                result *= 10;
        !           607:                exp--;
        !           608:        }
        !           609:   
        !           610:        return result;
        !           611: }
        !           612: 
        !           613: static LLONG ROUND(LDOUBLE value)
        !           614: {
        !           615:        LLONG intpart;
        !           616: 
        !           617:        intpart = (LLONG)value;
        !           618:        value = value - intpart;
        !           619:        if (value >= 0.5) intpart++;
        !           620:        
        !           621:        return intpart;
        !           622: }
        !           623: 
        !           624: /* a replacement for modf that doesn't need the math library. Should
        !           625:    be portable, but slow */
        !           626: static double my_modf(double x0, double *iptr)
        !           627: {
        !           628:        int i;
        !           629:        long l;
        !           630:        double x = x0;
        !           631:        double f = 1.0;
        !           632: 
        !           633:        for (i=0;i<100;i++) {
        !           634:                l = (long)x;
        !           635:                if (l <= (x+1) && l >= (x-1)) {
        !           636:                        if (i != 0) {
        !           637:                                double i2;
        !           638:                                double ret;
        !           639: 
        !           640:                                ret = my_modf(x0-l*f, &i2);
        !           641:                                (*iptr) = l*f + i2;
        !           642:                                return ret;
        !           643:                        } 
        !           644: 
        !           645:                        (*iptr) = l;
        !           646:                        return x - (*iptr);
        !           647:                }
        !           648:                x *= 0.1;
        !           649:                f *= 10.0;
        !           650:        }
        !           651: 
        !           652:        /* yikes! the number is beyond what we can handle. What do we do? */
        !           653:        (*iptr) = 0;
        !           654:        return 0;
        !           655: }
        !           656: 
        !           657: 
        !           658: static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
        !           659:                   LDOUBLE fvalue, int min, int max, int flags)
        !           660: {
        !           661:        int signvalue = 0;
        !           662:        double ufvalue;
        !           663:        char iconvert[311];
        !           664:        char fconvert[311];
        !           665:        int iplace = 0;
        !           666:        int fplace = 0;
        !           667:        int padlen = 0; /* amount to pad */
        !           668:        int zpadlen = 0; 
        !           669:        int caps = 0;
        !           670:        int idx;
        !           671:        double intpart;
        !           672:        double fracpart;
        !           673:        double temp;
        !           674:   
        !           675:        /* 
        !           676:         * AIX manpage says the default is 0, but Solaris says the default
        !           677:         * is 6, and sprintf on AIX defaults to 6
        !           678:         */
        !           679:        if (max < 0)
        !           680:                max = 6;
        !           681: 
        !           682:        ufvalue = abs_val (fvalue);
        !           683: 
        !           684:        if (fvalue < 0) {
        !           685:                signvalue = '-';
        !           686:        } else {
        !           687:                if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
        !           688:                        signvalue = '+';
        !           689:                } else {
        !           690:                        if (flags & DP_F_SPACE)
        !           691:                                signvalue = ' ';
        !           692:                }
        !           693:        }
        !           694: 
        !           695: #if 0
        !           696:        if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
        !           697: #endif
        !           698: 
        !           699: #if 0
        !           700:         if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */
        !           701: #endif
        !           702: 
        !           703:        /* 
        !           704:         * Sorry, we only support 16 digits past the decimal because of our 
        !           705:         * conversion method
        !           706:         */
        !           707:        if (max > 16)
        !           708:                max = 16;
        !           709: 
        !           710:        /* We "cheat" by converting the fractional part to integer by
        !           711:         * multiplying by a factor of 10
        !           712:         */
        !           713: 
        !           714:        temp = ufvalue;
        !           715:        my_modf(temp, &intpart);
        !           716: 
        !           717:        fracpart = ROUND((POW10(max)) * (ufvalue - intpart));
        !           718:        
        !           719:        if (fracpart >= POW10(max)) {
        !           720:                intpart++;
        !           721:                fracpart -= POW10(max);
        !           722:        }
        !           723: 
        !           724: 
        !           725:        /* Convert integer part */
        !           726:        do {
        !           727:                temp = intpart*0.1;
        !           728:                my_modf(temp, &intpart);
        !           729:                idx = (int) ((temp -intpart +0.05)* 10.0);
        !           730:                /* idx = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */
        !           731:                /* printf ("%llf, %f, %x\n", temp, intpart, idx); */
        !           732:                iconvert[iplace++] =
        !           733:                        (caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
        !           734:        } while (intpart && (iplace < 311));
        !           735:        if (iplace == 311) iplace--;
        !           736:        iconvert[iplace] = 0;
        !           737: 
        !           738:        /* Convert fractional part */
        !           739:        if (fracpart)
        !           740:        {
        !           741:                do {
        !           742:                        temp = fracpart*0.1;
        !           743:                        my_modf(temp, &fracpart);
        !           744:                        idx = (int) ((temp -fracpart +0.05)* 10.0);
        !           745:                        /* idx = (int) ((((temp/10) -fracpart) +0.05) *10); */
        !           746:                        /* printf ("%lf, %lf, %ld\n", temp, fracpart, idx ); */
        !           747:                        fconvert[fplace++] =
        !           748:                        (caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
        !           749:                } while(fracpart && (fplace < 311));
        !           750:                if (fplace == 311) fplace--;
        !           751:        }
        !           752:        fconvert[fplace] = 0;
        !           753:   
        !           754:        /* -1 for decimal point, another -1 if we are printing a sign */
        !           755:        padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); 
        !           756:        zpadlen = max - fplace;
        !           757:        if (zpadlen < 0) zpadlen = 0;
        !           758:        if (padlen < 0) 
        !           759:                padlen = 0;
        !           760:        if (flags & DP_F_MINUS) 
        !           761:                padlen = -padlen; /* Left Justifty */
        !           762:        
        !           763:        if ((flags & DP_F_ZERO) && (padlen > 0)) {
        !           764:                if (signvalue) {
        !           765:                        dopr_outch (buffer, currlen, maxlen, signvalue);
        !           766:                        --padlen;
        !           767:                        signvalue = 0;
        !           768:                }
        !           769:                while (padlen > 0) {
        !           770:                        dopr_outch (buffer, currlen, maxlen, '0');
        !           771:                        --padlen;
        !           772:                }
        !           773:        }
        !           774:        while (padlen > 0) {
        !           775:                dopr_outch (buffer, currlen, maxlen, ' ');
        !           776:                --padlen;
        !           777:        }
        !           778:        if (signvalue) 
        !           779:                dopr_outch (buffer, currlen, maxlen, signvalue);
        !           780:        
        !           781:        while (iplace > 0) 
        !           782:                dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
        !           783: 
        !           784: #ifdef DEBUG_SNPRINTF
        !           785:        printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
        !           786: #endif
        !           787: 
        !           788:        /*
        !           789:         * Decimal point.  This should probably use locale to find the correct
        !           790:         * char to print out.
        !           791:         */
        !           792:        if (max > 0) {
        !           793:                dopr_outch (buffer, currlen, maxlen, '.');
        !           794:                
        !           795:                while (zpadlen > 0) {
        !           796:                        dopr_outch (buffer, currlen, maxlen, '0');
        !           797:                        --zpadlen;
        !           798:                }
        !           799: 
        !           800:                while (fplace > 0) 
        !           801:                        dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
        !           802:        }
        !           803: 
        !           804:        while (padlen < 0) {
        !           805:                dopr_outch (buffer, currlen, maxlen, ' ');
        !           806:                ++padlen;
        !           807:        }
        !           808: }
        !           809: 
        !           810: static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
        !           811: {
        !           812:        if (*currlen < maxlen) {
        !           813:                buffer[(*currlen)] = c;
        !           814:        }
        !           815:        (*currlen)++;
        !           816: }
        !           817: 
        !           818:  int rsync_vsnprintf (char *str, size_t count, const char *fmt, va_list args)
        !           819: {
        !           820:        return dopr(str, count, fmt, args);
        !           821: }
        !           822: #define vsnprintf rsync_vsnprintf
        !           823: #endif
        !           824: 
        !           825: /* yes this really must be a ||. Don't muck with this (tridge)
        !           826:  *
        !           827:  * The logic for these two is that we need our own definition if the
        !           828:  * OS *either* has no definition of *sprintf, or if it does have one
        !           829:  * that doesn't work properly according to the autoconf test.
        !           830:  */
        !           831: #if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
        !           832: int rsync_snprintf(char *str,size_t count,const char *fmt,...)
        !           833: {
        !           834:        size_t ret;
        !           835:        va_list ap;
        !           836:     
        !           837:        va_start(ap, fmt);
        !           838:        ret = vsnprintf(str, count, fmt, ap);
        !           839:        va_end(ap);
        !           840:        return ret;
        !           841: }
        !           842: #define snprintf rsync_snprintf
        !           843: #endif
        !           844: 
        !           845: #endif 
        !           846: 
        !           847: #ifndef HAVE_VASPRINTF
        !           848:  int vasprintf(char **ptr, const char *format, va_list ap)
        !           849: {
        !           850:        int ret;
        !           851:        va_list ap2;
        !           852: 
        !           853:        VA_COPY(ap2, ap);
        !           854:        
        !           855:        ret = vsnprintf(NULL, 0, format, ap2);
        !           856:        if (ret <= 0) return ret;
        !           857: 
        !           858:        (*ptr) = (char *)malloc(ret+1);
        !           859:        if (!*ptr) return -1;
        !           860: 
        !           861:        VA_COPY(ap2, ap);
        !           862: 
        !           863:        ret = vsnprintf(*ptr, ret+1, format, ap2);
        !           864: 
        !           865:        return ret;
        !           866: }
        !           867: #endif
        !           868: 
        !           869: 
        !           870: #ifndef HAVE_ASPRINTF
        !           871:  int asprintf(char **ptr, const char *format, ...)
        !           872: {
        !           873:        va_list ap;
        !           874:        int ret;
        !           875:        
        !           876:        *ptr = NULL;
        !           877:        va_start(ap, format);
        !           878:        ret = vasprintf(ptr, format, ap);
        !           879:        va_end(ap);
        !           880: 
        !           881:        return ret;
        !           882: }
        !           883: #endif
        !           884: 
        !           885: #ifdef TEST_SNPRINTF
        !           886: 
        !           887:  int sprintf(char *str,const char *fmt,...);
        !           888: 
        !           889:  int main (void)
        !           890: {
        !           891:        char buf1[1024];
        !           892:        char buf2[1024];
        !           893:        char *fp_fmt[] = {
        !           894:                "%1.1f",
        !           895:                "%-1.5f",
        !           896:                "%1.5f",
        !           897:                "%123.9f",
        !           898:                "%10.5f",
        !           899:                "% 10.5f",
        !           900:                "%+22.9f",
        !           901:                "%+4.9f",
        !           902:                "%01.3f",
        !           903:                "%4f",
        !           904:                "%3.1f",
        !           905:                "%3.2f",
        !           906:                "%.0f",
        !           907:                "%f",
        !           908:                "-16.16f",
        !           909:                NULL
        !           910:        };
        !           911:        double fp_nums[] = { 6442452944.1234, -1.5, 134.21, 91340.2, 341.1234, 203.9, 0.96, 0.996, 
        !           912:                             0.9996, 1.996, 4.136, 5.030201, 0.00205,
        !           913:                             /* END LIST */ 0};
        !           914:        char *int_fmt[] = {
        !           915:                "%-1.5d",
        !           916:                "%1.5d",
        !           917:                "%123.9d",
        !           918:                "%5.5d",
        !           919:                "%10.5d",
        !           920:                "% 10.5d",
        !           921:                "%+22.33d",
        !           922:                "%01.3d",
        !           923:                "%4d",
        !           924:                "%d",
        !           925:                NULL
        !           926:        };
        !           927:        long int_nums[] = { -1, 134, 91340, 341, 0203, 0};
        !           928:        char *str_fmt[] = {
        !           929:                "10.5s",
        !           930:                "5.10s",
        !           931:                "10.1s",
        !           932:                "0.10s",
        !           933:                "10.0s",
        !           934:                "1.10s",
        !           935:                "%s",
        !           936:                "%.1s",
        !           937:                "%.10s",
        !           938:                "%10s",
        !           939:                NULL
        !           940:        };
        !           941:        char *str_vals[] = {"hello", "a", "", "a longer string", NULL};
        !           942:        int x, y;
        !           943:        int fail = 0;
        !           944:        int num = 0;
        !           945: 
        !           946:        printf ("Testing snprintf format codes against system sprintf...\n");
        !           947: 
        !           948:        for (x = 0; fp_fmt[x] ; x++) {
        !           949:                for (y = 0; fp_nums[y] != 0 ; y++) {
        !           950:                        int l1 = snprintf(NULL, 0, fp_fmt[x], fp_nums[y]);
        !           951:                        int l2 = snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);
        !           952:                        sprintf (buf2, fp_fmt[x], fp_nums[y]);
        !           953:                        if (strcmp (buf1, buf2)) {
        !           954:                                printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n", 
        !           955:                                       fp_fmt[x], buf1, buf2);
        !           956:                                fail++;
        !           957:                        }
        !           958:                        if (l1 != l2) {
        !           959:                                printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, fp_fmt[x]);
        !           960:                                fail++;
        !           961:                        }
        !           962:                        num++;
        !           963:                }
        !           964:        }
        !           965: 
        !           966:        for (x = 0; int_fmt[x] ; x++) {
        !           967:                for (y = 0; int_nums[y] != 0 ; y++) {
        !           968:                        int l1 = snprintf(NULL, 0, int_fmt[x], int_nums[y]);
        !           969:                        int l2 = snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);
        !           970:                        sprintf (buf2, int_fmt[x], int_nums[y]);
        !           971:                        if (strcmp (buf1, buf2)) {
        !           972:                                printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n", 
        !           973:                                       int_fmt[x], buf1, buf2);
        !           974:                                fail++;
        !           975:                        }
        !           976:                        if (l1 != l2) {
        !           977:                                printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, int_fmt[x]);
        !           978:                                fail++;
        !           979:                        }
        !           980:                        num++;
        !           981:                }
        !           982:        }
        !           983: 
        !           984:        for (x = 0; str_fmt[x] ; x++) {
        !           985:                for (y = 0; str_vals[y] != 0 ; y++) {
        !           986:                        int l1 = snprintf(NULL, 0, str_fmt[x], str_vals[y]);
        !           987:                        int l2 = snprintf(buf1, sizeof(buf1), str_fmt[x], str_vals[y]);
        !           988:                        sprintf (buf2, str_fmt[x], str_vals[y]);
        !           989:                        if (strcmp (buf1, buf2)) {
        !           990:                                printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n", 
        !           991:                                       str_fmt[x], buf1, buf2);
        !           992:                                fail++;
        !           993:                        }
        !           994:                        if (l1 != l2) {
        !           995:                                printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, str_fmt[x]);
        !           996:                                fail++;
        !           997:                        }
        !           998:                        num++;
        !           999:                }
        !          1000:        }
        !          1001: 
        !          1002:        printf ("%d tests failed out of %d.\n", fail, num);
        !          1003: 
        !          1004:        printf("seeing how many digits we support\n");
        !          1005:        {
        !          1006:                double v0 = 0.12345678901234567890123456789012345678901;
        !          1007:                for (x=0; x<100; x++) {
        !          1008:                        double p = pow(10, x); 
        !          1009:                        double r = v0*p;
        !          1010:                        snprintf(buf1, sizeof(buf1), "%1.1f", r);
        !          1011:                        sprintf(buf2,                "%1.1f", r);
        !          1012:                        if (strcmp(buf1, buf2)) {
        !          1013:                                printf("we seem to support %d digits\n", x-1);
        !          1014:                                break;
        !          1015:                        }
        !          1016:                }
        !          1017:        }
        !          1018: 
        !          1019:        return 0;
        !          1020: }
        !          1021: #endif /* TEST_SNPRINTF */

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