Annotation of embedaddon/rsync/lib/snprintf.c, revision 1.1.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>