/* * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef LIBMONETRA_INTERNAL #ifdef HAVE_CONFIG_H #ifdef _WIN32 #include "win32config.h" #else /* _WIN32 */ #include "config.h" #endif /* _WIN32 */ #endif /* HAVE_CONFIG_H */ #endif /* LIBMONETRA_INTERNAL */ //#define SNPRINTF_TEST //#define USE_INTERNAL_SPRINTF_FLOAT #ifdef M_INTERNAL #include "monetra.h" #elif defined(LIBMONETRA_INTERNAL) #include #ifndef _WIN32 #include #else #include #include #define write(a,b,c) _write(a,b,c) #endif #include #include #define M_malloc(a) malloc(a) #define M_realloc(a,b) realloc(a,b) #define M_free(a) free(a) #include "monetra.h" #else #include #include #include #include #define M_malloc(a) malloc(a) #define M_realloc(a,b) realloc(a,b) #define M_free(a) free(a) #endif #include #ifndef _WIN32 #include #include #endif /* * We do all internal arithmetic in the widest available integer type, * here called long_long (or ulong_long for unsigned). */ #ifdef M_INTERNAL typedef M_int64 long_long; typedef M_uint64 ulong_long; #elif defined(LIBMONETRA_INTERNAL) typedef M_int64 long_long; typedef M_uint64 ulong_long; #else # ifdef HAVE_STDINT_H # include typedef int64_t long_long; typedef uint64_t ulong_long; # else /* !HAVE_STDINT_H */ # ifdef _WIN32 typedef signed __int64 long_long; typedef unsigned __int64 ulong_long; # else /* !WIN32 */ # ifndef NO_LONG_LONG typedef long long long_long; typedef unsigned long long ulong_long; # else /* NO_LONG_LONG */ typedef long long_long; typedef unsigned long ulong_long; # endif /* NO_LONG_LONG */ # endif /* !WIN32 */ # endif /* HAVE_STDINT_H */ #endif /* M_INTERNAL */ /* ** SNPRINTF, VSNPRINT -- counted versions of printf ** ** These versions have been grabbed off the net. They have been ** cleaned up to compile properly and support for .precision and ** %lx has been added. */ /************************************************************** * Original: * Patrick Powell Tue Apr 11 09:48:21 PDT 1995 * A bombproof version of doprnt (dopr) included. * Sigh. This sort of thing is always nasty do deal with. Note that * the version here does not include floating point. (now it does ... tgl) * * snprintf() is used instead of sprintf() as it does limit checks * for string length. This covers a nasty loophole. * * The other functions are there to prevent NULL pointers from * causing nast effects. **************************************************************/ /*static char _id[] = "$Id: libmonetra_snprintf.c,v 1.11 2005/07/14 16:29:39 brad Exp $";*/ #define vsnprintf_none 0 #define vsnprintf_buf 1 #define vsnprintf_fd 2 #define vsnprintf_fp 3 #define VSNPRINTF_CACHE_SIZE 512 typedef struct _vsnprintf_interal_st { int out_type; int fd; FILE *fp; char *buf; long buf_size; char temp[VSNPRINTF_CACHE_SIZE]; int temp_cnt; long cnt; int overflow; } _vsnprintf_internal_st; int vsnprintf_init_st(_vsnprintf_internal_st *st) { st->out_type=vsnprintf_none; st->fd=-1; st->fp=NULL; st->buf=NULL; st->buf_size=0; memset(st->temp, 0, sizeof(st->temp)); st->temp_cnt=0; st->cnt=0; st->overflow=0; return(1); } static void vsnprintf_flush_cache(_vsnprintf_internal_st *st) { if (st->temp_cnt <= 0) return; if (st->out_type == vsnprintf_fd) { if (st->fd != -1) { write(st->fd, st->temp, st->temp_cnt); st->cnt+=st->temp_cnt; } else { st->overflow+=st->temp_cnt; } } else if (st->out_type == vsnprintf_fp) { if (st->fp != NULL) { fwrite(st->temp, sizeof(char), st->temp_cnt, st->fp); st->cnt+=st->temp_cnt; } else { st->overflow+=st->temp_cnt; } } else { return; } memset(st->temp, 0, sizeof(st->temp)); st->temp_cnt=0; } static int M_vsnprintf_internal(char *str, size_t count, const char *fmt, va_list args, int *overflow); static void dopr(_vsnprintf_internal_st *st, const char *format, va_list args); static int M_vsnprintf_internal(char *str, size_t count, const char *fmt, va_list args, int *overflow) { _vsnprintf_internal_st st; vsnprintf_init_st(&st); st.out_type=vsnprintf_buf; st.buf=str; st.buf_size=count; st.buf[0] = '\0'; dopr(&st, fmt, args); if (overflow != NULL) { *overflow=st.overflow; } st.buf[(st.buf_size-1)]='\0'; return (st.cnt); } int M_vsnprintf(char *str, size_t count, const char *fmt, va_list args) { return(M_vsnprintf_internal(str, count, fmt, args, NULL)); } int M_snprintf(char *str, size_t count, const char *fmt,...) { int len; va_list args; va_start(args, fmt); len = M_vsnprintf(str, count, fmt, args); va_end(args); return len; } #define CHUNKSIZE 512 /* Not all systems have va_copy, so we need to pass 2 initialized instances * of the va_list to account for the first scan which does a count, and the * second pass which allocates and writes to the buffer */ int M_vasprintf_real(char **ret, const char *fmt, va_list args, va_list args2, char *file, long line) { int chunks; size_t buflen; char *buf; int len; int overflow=0; int first=1; chunks = ((strlen(fmt) + 1) / CHUNKSIZE) + 1; buflen = chunks * CHUNKSIZE; /* SHOULD ONLY LOOP ONCE AS WE'RE GRABBING THE OVERFLOW FROM THE INTERNAL VSNPRINTF */ while (1) { #ifdef MEM_DEBUG if ((buf = MemTrace_malloc(buflen, file, line, 0)) == NULL) { #else if ((buf = M_malloc(buflen)) == NULL) { #endif *ret = NULL; return -1; } overflow=0; if (first) { len = M_vsnprintf_internal(buf, buflen, fmt, args, &overflow); first=0; } else { len = M_vsnprintf_internal(buf, buflen, fmt, args2, &overflow); } if (overflow) { M_free(buf); buf=NULL; buflen+=(overflow+1); } else { break; } } *ret = buf; return len; } #ifdef _WIN32 int M_asprintf(char **ret, const char *fmt, ...) { int len; va_list ap, ap2; va_start(ap, fmt); va_start(ap2, fmt); len=M_vasprintf_real(ret, fmt, ap, ap2, "WIN32 DOESN'T KNOW", 666); va_end(ap); va_end(ap2); return(len); } #else int M_asprintf_real(char *file, long line, char **ret, const char *fmt, ...) { int len; va_list ap, ap2; va_start(ap, fmt); va_start(ap2, fmt); len=M_vasprintf_real(ret, fmt, ap, ap2, file, line); va_end(ap); va_end(ap2); return(len); } #endif int M_vfprintf(FILE *fp, const char *fmt, va_list args) { _vsnprintf_internal_st st; vsnprintf_init_st(&st); st.out_type=vsnprintf_fp; st.fp=fp; dopr(&st, fmt, args); vsnprintf_flush_cache(&st); return (st.cnt); } int M_fprintf(FILE *fp, const char *fmt, ...) { int len; va_list ap; va_start(ap, fmt); len=M_vfprintf(fp, fmt, ap); va_end(ap); return(len); } int M_vprintf(const char *fmt, va_list args) { _vsnprintf_internal_st st; vsnprintf_init_st(&st); st.out_type=vsnprintf_fd; st.fd=0; dopr(&st, fmt, args); vsnprintf_flush_cache(&st); return(st.cnt); } int M_printf(const char *fmt, ...) { int len; va_list ap; va_start(ap, fmt); len=M_vprintf(fmt, ap); va_end(ap); return(len); } /* * dopr(): poor man's version of doprintf */ static void fmtstr(char *value, int ljust, int len, int zpad, int maxwidth, _vsnprintf_internal_st *st); static void fmtnum(long_long value, int base, int dosign, int ljust, int len, int zpad, _vsnprintf_internal_st *st); static void fmtfloat(double value, char type, int ljust, int len, int precision, int pointflag, int zpad, _vsnprintf_internal_st *st); static void dostr(const char *str, int cut, _vsnprintf_internal_st *st); static void dopr_outch(int c, _vsnprintf_internal_st *st); static void dopr_outch_multi(int c, int cnt, _vsnprintf_internal_st *st); static void vsnprintf_term_current(_vsnprintf_internal_st *st) { if (st->out_type == vsnprintf_buf) { st->buf[st->cnt]=0; } } static void dopr(_vsnprintf_internal_st *st, const char *format, va_list args) { int ch; long_long value; double fvalue; int longlongflag = 0; int longflag = 0; int pointflag = 0; int maxwidth = 0; char *strvalue; int ljust; int len; int zpad; const char *str_start=NULL; while ((ch = *format++)) { switch (ch) { case '%': if (str_start) { dostr(str_start, (format-str_start)-1, st); str_start=NULL; } ljust = len = zpad = maxwidth = 0; longflag = longlongflag = pointflag = 0; nextch: ch = *format++; switch (ch) { case 0: dostr("**end of format**", 0, st); vsnprintf_term_current(st); return; case '-': ljust = 1; goto nextch; case '0': /* set zero padding if len not set */ if (len == 0 && !pointflag) zpad = '0'; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (pointflag) maxwidth = maxwidth * 10 + ch - '0'; else len = len * 10 + ch - '0'; goto nextch; case '*': if (pointflag) maxwidth = va_arg(args, int); else len = va_arg(args, int); goto nextch; case '.': pointflag = 1; goto nextch; case 'l': if (longflag) longlongflag = 1; else longflag = 1; goto nextch; case 'u': case 'U': /* fmtnum(value,base,dosign,ljust,len,zpad) */ if (longflag) { if (longlongflag) value = va_arg(args, ulong_long); else value = va_arg(args, unsigned long); } else value = va_arg(args, unsigned int); fmtnum(value, 10, 0, ljust, len, zpad, st); break; case 'o': case 'O': /* fmtnum(value,base,dosign,ljust,len,zpad) */ if (longflag) { if (longlongflag) value = va_arg(args, ulong_long); else value = va_arg(args, unsigned long); } else value = va_arg(args, unsigned int); fmtnum(value, 8, 0, ljust, len, zpad, st); break; case 'i': case 'd': case 'D': if (longflag) { if (longlongflag) value = va_arg(args, long_long); else value = va_arg(args, long); } else value = va_arg(args, int); fmtnum(value, 10, 1, ljust, len, zpad, st); break; case 'x': if (longflag) { if (longlongflag) value = va_arg(args, ulong_long); else value = va_arg(args, unsigned long); } else value = va_arg(args, unsigned int); fmtnum(value, 16, 0, ljust, len, zpad, st); break; case 'X': if (longflag) { if (longlongflag) value = va_arg(args, ulong_long); else value = va_arg(args, unsigned long); } else value = va_arg(args, unsigned int); fmtnum(value, -16, 0, ljust, len, zpad, st); break; case 's': strvalue = va_arg(args, char *); if (maxwidth > 0 || !pointflag) { if (pointflag && len > maxwidth) len = maxwidth; /* Adjust padding */ fmtstr(strvalue, ljust, len, zpad, maxwidth, st); } break; case 'c': ch = va_arg(args, int); dopr_outch(ch, st); break; case 'e': case 'E': case 'f': case 'g': case 'G': fvalue = va_arg(args, double); fmtfloat(fvalue, (char)ch, ljust, len, maxwidth, pointflag, zpad, st); break; case '%': dopr_outch(ch, st); continue; default: dostr("???????", 0, st); } break; default: if (str_start == NULL) { str_start=format-1; } break; } } if (str_start) { dostr(str_start, (format-str_start)-1, st); str_start=NULL; } vsnprintf_term_current(st); } static void fmtstr(char *value, int ljust, int len, int zpad, int maxwidth, _vsnprintf_internal_st *st) { int padlen, strlen; /* amount to pad */ if (value == 0) value = ""; for (strlen = 0; value[strlen]; ++strlen); /* strlen */ if (strlen > maxwidth && maxwidth) strlen = maxwidth; padlen = len - strlen; if (padlen < 0) padlen = 0; if (ljust) padlen = -padlen; if (padlen > 0) { dopr_outch_multi(' ', padlen, st); padlen=0; } dostr(value, maxwidth, st); dopr_outch_multi(' ', -padlen, st); } static void fmtnum(long_long value, int base, int dosign, int ljust, int len, int zpad, _vsnprintf_internal_st *st) { int signvalue = 0; ulong_long uvalue; char convert[64]; int place = 0; int padlen = 0; /* amount to pad */ int caps = 0; int i,c; /* * DEBUGP(("value 0x%x, base %d, dosign %d, ljust %d, len %d, zpad * %d\n", value, base, dosign, ljust, len, zpad )); */ uvalue = value; if (dosign) { if (value < 0) { signvalue = '-'; uvalue = -value; } } if (base < 0) { caps = 1; base = -base; } do { convert[place++] = (caps ? "0123456789ABCDEF" : "0123456789abcdef") [uvalue % (unsigned) base]; uvalue = (uvalue / (unsigned) base); } while (uvalue); convert[place] = 0; if (len < 0) { /* this could happen with a "*" width spec */ ljust = 1; len = -len; } padlen = len - place; if (padlen < 0) padlen = 0; if (ljust) padlen = -padlen; /* * DEBUGP(( "str '%s', place %d, sign %c, padlen %d\n", * convert,place,signvalue,padlen)); */ if (zpad && padlen > 0) { if (signvalue) { dopr_outch(signvalue, st); --padlen; signvalue = 0; } if (padlen > 0) { dopr_outch_multi(zpad, padlen, st); padlen=0; } } if (padlen > 0) { dopr_outch_multi(' ', padlen, st); padlen=0; } if (signvalue) dopr_outch(signvalue, st); /* Must reverse convert, as it is in reverse order */ for (i=0; i= place-i) break; c=convert[i]; convert[i]=convert[place-i-1]; convert[place-i-1]=c; } dostr(convert, place, st); if (padlen < 0) { dopr_outch_multi(' ', -padlen, st); padlen=0; } } /* ADAPT FLOATING POINT PRINTING FROM SAMBA's snprintf() */ /* a replacement for modf that doesn't need the math library. Should be portable, but slow */ static double my_modf(double x0, double *iptr) { int i; long l; double x = x0; double f = 1.0; for (i=0;i<100;i++) { l = (long)x; if (l <= (x+1) && l >= (x-1)) break; x *= 0.1; f *= 10.0; } if (i == 100) { /* yikes! the number is beyond what we can handle. What do we do? */ (*iptr) = 0; return 0; } if (i != 0) { double i2; double ret; ret = my_modf(x0-l*f, &i2); (*iptr) = l*f + i2; return ret; } (*iptr) = l; return x - (*iptr); } static double POW10(int exp) { double result = 1; while (exp) { result *= 10; exp--; } return result; } static long_long ROUND(double value) { long_long intpart; intpart = (long_long)value; value = value - intpart; if (value >= 0.5) intpart++; return intpart; } #define abs_val(a) (a >= 0)?a:(-a) static void fmtfloat_real(char *convert, int conv_len, double fvalue, char type, int ljust, int len, int max, int pointflag, int zpad) { double ufvalue; char iconvert[311]; char fconvert[311]; int iplace = 0; int fplace = 0; int zpadlen = 0; int caps = 0; int index; double intpart; double fracpart; double temp; int curlen=0; /* * AIX manpage says the default is 0, but Solaris says the default * is 6, and sprintf on AIX defaults to 6 */ if (max < 0 || !pointflag) max = 6; ufvalue = abs_val (fvalue); /* * Sorry, we only support 16 digits past the decimal because of our * conversion method */ if (max > 16) max = 16; /* We "cheat" by converting the fractional part to integer by * multiplying by a factor of 10 */ temp = ufvalue; my_modf(temp, &intpart); fracpart = (double)ROUND((POW10(max)) * (ufvalue - intpart)); if (fracpart >= POW10(max)) { intpart++; fracpart -= POW10(max); } /* Convert integer part */ do { temp = intpart; my_modf(intpart*0.1, &intpart); temp = temp*0.1; index = (int) ((temp -intpart +0.05)* 10.0); /* index = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */ /* printf ("%llf, %f, %x\n", temp, intpart, index); */ iconvert[iplace++] = (caps? "0123456789ABCDEF":"0123456789abcdef")[index]; } while (intpart && (iplace < 311)); if (iplace == 311) iplace--; iconvert[iplace] = 0; /* Convert fractional part */ if (fracpart) { do { temp = fracpart; my_modf(fracpart*0.1, &fracpart); temp = temp*0.1; index = (int) ((temp -fracpart +0.05)* 10.0); /* index = (int) ((((temp/10) -fracpart) +0.05) *10); */ /* printf ("%lf, %lf, %ld\n", temp, fracpart, index); */ fconvert[fplace++] = (caps? "0123456789ABCDEF":"0123456789abcdef")[index]; } while(fracpart && (fplace < 311)); if (fplace == 311) fplace--; } fconvert[fplace] = 0; zpadlen = max - fplace; if (zpadlen < 0) zpadlen = 0; while (iplace > 0) if (curlen < conv_len) convert[curlen++]=iconvert[--iplace]; /* * Decimal point. This should probably use locale to find the correct * char to print out. */ if (max > 0) { if (curlen < conv_len) convert[curlen++]='.'; while (zpadlen > 0) { if (curlen < conv_len) convert[curlen++]='0'; --zpadlen; } while (fplace > 0) if (curlen < conv_len) convert[curlen++]=fconvert[--fplace]; } convert[curlen]=0; } static void fmtfloat(double value, char type, int ljust, int len, int precision, int pointflag, int zpad, _vsnprintf_internal_st *st) { char convert[512]; int padlen = 0; /* amount to pad */ int isneg=0; #ifdef USE_INTERNAL_SPRINTF_FLOAT char fmt[32]; /* we rely on regular C library's sprintf to do the basic conversion */ if (pointflag) sprintf(fmt, "%%.%d%c", precision, type); else sprintf(fmt, "%%%c", type); sprintf(convert, fmt, abs_val(value)); #else fmtfloat_real(convert, sizeof(convert), abs_val(value), type, ljust, len, precision, pointflag, zpad); #endif if (len < 0) { /* this could happen with a "*" width spec */ ljust = 1; len = -len; } if (value < 0) isneg=1; if (isneg) padlen = len - strlen(convert) - 1; else padlen = len - strlen(convert); if (padlen < 0) padlen = 0; if (ljust) padlen = -padlen; if (isneg && zpad) dopr_outch('-', st); if (padlen > 0) { if (zpad) dopr_outch_multi(zpad, padlen, st); else dopr_outch_multi(' ', padlen, st); padlen=0; } if (isneg && !zpad) dopr_outch('-', st); dostr(convert, 0, st); if (padlen < 0) { if (zpad) dopr_outch_multi(zpad, -padlen, st); else dopr_outch_multi(' ', -padlen, st); padlen=0; } } static void dostr(const char *str, int maxwidth, _vsnprintf_internal_st *st) { #if 0 if (cut) { while (*str && cut-- > 0) dopr_outch(*str++, st); } else { while (*str) dopr_outch(*str++, st); } #else /* Optimization over old way so we don't call dopr_outch so many times */ int str_len=0, memcpy_len=0; const char *ptr=str; while (1) { str_len=strlen(ptr); if (maxwidth && (ptr-str)+str_len > maxwidth) { str_len=maxwidth-(ptr-str); } if (str_len <= 0) break; if (st->out_type == vsnprintf_buf) { if ((st->buf_size - 1) - st->cnt >= str_len) { memcpy_len=str_len; } else { memcpy_len=(st->buf_size - 1) - st->cnt; } } else if (st->out_type == vsnprintf_fd || st->out_type == vsnprintf_fp) { if (((VSNPRINTF_CACHE_SIZE-1) - st->temp_cnt) >= str_len) { memcpy_len=str_len; } else { memcpy_len=(VSNPRINTF_CACHE_SIZE - 1) - st->temp_cnt; } } else { /* We really don't have an output buffer here */ /* vsnprintf_none */ memcpy_len=str_len; } if (memcpy_len == 0 && st->out_type == vsnprintf_buf) { st->overflow+=str_len; break; } else if (memcpy_len == 0 && (st->out_type == vsnprintf_fd || st->out_type == vsnprintf_fp) ) { vsnprintf_flush_cache(st); /* We need to loop again. Had to flush the cache */ } else { if (st->out_type == vsnprintf_buf) { memcpy(st->buf+st->cnt, ptr, memcpy_len); st->cnt+=memcpy_len; } else if (st->out_type == vsnprintf_fd || st->out_type == vsnprintf_fp) { memcpy(st->temp+st->temp_cnt, ptr, memcpy_len); st->temp_cnt+=memcpy_len; if (memcpy_len != str_len) { vsnprintf_flush_cache(st); } } else { /* vsnprintf_none */ st->overflow+=memcpy_len; } } if (memcpy_len == str_len) { /* If we've written the whole thing, break out*/ break; } else { /* Increment the str so we can determine how many bytes are left */ ptr+=memcpy_len; } } #endif } static void dopr_outch_multi(int c, int cnt, _vsnprintf_internal_st *st) { int memset_len=0; int b_left=cnt; if (cnt <= 0) return; if (cnt == 1) { dopr_outch(c,st); return; } while (1) { if (st->out_type == vsnprintf_buf) { if ((st->buf_size - 1) - st->cnt >= b_left) { memset_len=b_left; } else { memset_len=(st->buf_size - 1) - st->cnt; } } else if (st->out_type == vsnprintf_fd || st->out_type == vsnprintf_fp) { if (((VSNPRINTF_CACHE_SIZE-1) - st->temp_cnt) >= b_left) { memset_len=b_left; } else { memset_len=(VSNPRINTF_CACHE_SIZE - 1) - st->temp_cnt; } } else { /* We really don't have an output buffer here */ /* vsnprintf_none */ memset_len=b_left; } if (memset_len == 0 && st->out_type == vsnprintf_buf) { st->overflow+=b_left; break; } else if (memset_len == 0 && (st->out_type == vsnprintf_fd || st->out_type == vsnprintf_fp) ) { vsnprintf_flush_cache(st); /* We need to loop again. Had to flush the cache */ } else { if (st->out_type == vsnprintf_buf) { memset(st->buf+st->cnt, c, memset_len); st->cnt+=memset_len; } else if (st->out_type == vsnprintf_fd || st->out_type == vsnprintf_fp) { memset(st->temp+st->temp_cnt, c, memset_len); st->temp_cnt+=memset_len; /* We must need to flush it */ if (memset_len != b_left) { vsnprintf_flush_cache(st); } } else { /* vsnprintf_none */ st->overflow+=memset_len; } } if (memset_len == b_left) { /* If we've written the whole thing, break out*/ break; } else { /* decrement bytes left */ b_left-=memset_len; } } } static void dopr_outch(int c, _vsnprintf_internal_st *st) { if (st->out_type == vsnprintf_buf) { if (st->cnt < st->buf_size - 1) { st->buf[st->cnt] = c; st->cnt++; } else { st->overflow++; } } else if (st->out_type == vsnprintf_fd || st->out_type == vsnprintf_fp) { st->temp[st->temp_cnt] = c; st->temp_cnt++; if (st->temp_cnt == VSNPRINTF_CACHE_SIZE) { vsnprintf_flush_cache(st); } } else { /* Must be set to vsnprintf_none. All counts go to overflow */ st->overflow++; } }