/* *Infoaboutwheretheformattedoutputisgoing. * *doprandsubroutineswillnotwriteat/pastbufend,butsnprintf *reservesonebyte,ensuringitmayplacethetrailing'\0'there. * *Insnprintf,weusencharstocountthenumberofbytesdroppedonthe *floorduetobufferoverrun.Thecorrectresultofsnprintfisthus *(bufptr-bufstart)+nchars.(Thisisn'tasinconsistentasitmight *seem:ncharsisthenumberofemittedbytesthatarenotinthebuffernow, *eitherbecausewesentthemtothestreamorbecausewecouldn'tfitthem *intothebuffertobeginwith.)
*/ typedefstruct
{ char *bufptr; /* next buffer output position */ char *bufstart; /* first buffer element */ char *bufend; /* last+1 buffer element, or NULL */ /* bufend == NULL is for sprintf, where we assume buf is big enough */
FILE *stream; /* eventual output destination, or NULL */ int nchars; /* # chars sent to stream, or dropped */ bool failed; /* call is a failure; errno is set */
} PrintfTarget;
staticbool find_arguments(constchar *format, va_list args,
PrintfArgValue *argvalues); staticvoid fmtstr(constchar *value, int leftjust, int minlen, int maxwidth, int pointflag, PrintfTarget *target); staticvoid fmtptr(constvoid *value, PrintfTarget *target); staticvoid fmtint(longlong value, char type, int forcesign, int leftjust, int minlen, int zpad, int precision, int pointflag,
PrintfTarget *target); staticvoid fmtchar(int value, int leftjust, int minlen, PrintfTarget *target); staticvoid fmtfloat(double value, char type, int forcesign, int leftjust, int minlen, int zpad, int precision, int pointflag,
PrintfTarget *target); staticvoid dostr(constchar *str, int slen, PrintfTarget *target); staticvoid dopr_outch(int c, PrintfTarget *target); staticvoid dopr_outchmulti(int c, int slen, PrintfTarget *target); staticint adjust_sign(int is_negative, int forcesign, int *signvalue); staticint compute_padlen(int minlen, int vallen, int leftjust); staticvoid leading_pad(int zpad, int signvalue, int *padlen,
PrintfTarget *target); staticvoid trailing_pad(int padlen, PrintfTarget *target);
staticinlineconstchar *
strchrnul(constchar *s, int c)
{ while (*s != '\0' && *s != c)
s++; return s;
}
#endif/* !HAVE_DECL_STRCHRNUL */
/* *dopr():thegutsof*printfforallcases.
*/ staticvoid
dopr(PrintfTarget *target, constchar *format, va_list args)
{ int save_errno = errno; constchar *first_pct = NULL; int ch; bool have_dollar; bool have_star; bool afterstar; int accum; int longlongflag; int longflag; int pointflag; int leftjust; int fieldwidth; int precision; int zpad; int forcesign; int fmtpos; int cvalue; longlong numvalue; double fvalue; constchar *strvalue;
PrintfArgValue argvalues[PG_NL_ARGMAX + 1];
while (*format != '\0')
{ /* Locate next conversion specifier */ if (*format != '%')
{ /* Scan to next '%' or end of string */ constchar *next_pct = strchrnul(format + 1, '%');
/* Dump literal data we just scanned over */
dostr(format, next_pct - format, target); if (target->failed) break;
if (*next_pct == '\0') break;
format = next_pct;
}
/* *find_arguments():sortouttheargumentsforaformatspecwith%n$ * *Ifformatisvalid,returntrueandfillargvalues[i]withthevalue *fortheconversionspecthathas%i$or*i$.Elsereturnfalse.
*/ staticbool
find_arguments(constchar *format, va_list args,
PrintfArgValue *argvalues)
{ int ch; bool afterstar; int accum; int longlongflag; int longflag; int fmtpos; int i; int last_dollar = 0; /* Init to "no dollar arguments known" */
PrintfArgType argtypes[PG_NL_ARGMAX + 1] = {0};
/* *Thisloopmustacceptthesameformatstringsastheoneindopr(). *However,wedon'tneedtoanalyzethemtothesamelevelofdetail. * *Sincewe'reonlycalledifthere'sadollar-typespecsomewhere,wecan *failimmediatelyifwefindanon-dollarspec.PertheC99standard, *allargumentreferencesintheformatstringmustbeoneortheother.
*/ while (*format != '\0')
{ /* Locate next conversion specifier */ if (*format != '%')
{ /* Unlike dopr, we can just quit if there's no more specifiers */
format = strchr(format + 1, '%'); if (format == NULL) break;
}
/* Process conversion spec starting at *format */
format++;
longflag = longlongflag = 0;
fmtpos = accum = 0;
afterstar = false;
nextch1:
ch = *format++; switch (ch)
{ case'-': case'+': goto nextch1; case'0': case'1': case'2': case'3': case'4': case'5': case'6': case'7': case'8': case'9':
accum = accum * 10 + (ch - '0'); goto nextch1; case'.':
accum = 0; goto nextch1; case'*': if (afterstar) returnfalse; /* previous star missing dollar */
afterstar = true;
accum = 0; goto nextch1; case'$': if (accum <= 0 || accum > PG_NL_ARGMAX) returnfalse; if (afterstar)
{ if (argtypes[accum] &&
argtypes[accum] != ATYPE_INT) returnfalse;
argtypes[accum] = ATYPE_INT;
last_dollar = Max(last_dollar, accum);
afterstar = false;
} else
fmtpos = accum;
accum = 0; goto nextch1; #ifdef WIN32 case'I': /* Windows PRI*{32,64,PTR} size */ if (format[0] == '3' && format[1] == '2')
format += 2; elseif (format[0] == '6' && format[1] == '4')
{
format += 2;
longlongflag = 1;
} else
{ #if SIZEOF_VOID_P == SIZEOF_LONG
longflag = 1; #elif SIZEOF_VOID_P == SIZEOF_LONG_LONG
longlongflag = 1; #else #error"cannot find integer type of the same size as intptr_t" #endif
} goto nextch1; #endif case'l': if (longflag)
longlongflag = 1; else
longflag = 1; goto nextch1; case'z': #if SIZEOF_SIZE_T == SIZEOF_LONG
longflag = 1; #elif SIZEOF_SIZE_T == SIZEOF_LONG_LONG
longlongflag = 1; #else #error"cannot find integer type of the same size as size_t" #endif goto nextch1; case'h': case'\'': /* ignore these */ goto nextch1; case'd': case'i': case'o': case'u': case'x': case'X': if (fmtpos)
{
PrintfArgType atype;
/* *Formatappearsvalidsofar,socollecttheargumentsinphysical *order.(Sincewerejectedanynon-dollarspecsthatwouldhave *collectedarguments,weknowthatdopr()hasn'tcollectedanyyet.)
*/ for (i = 1; i <= last_dollar; i++)
{ switch (argtypes[i])
{ case ATYPE_NONE: returnfalse; case ATYPE_INT:
argvalues[i].i = va_arg(args, int); break; case ATYPE_LONG:
argvalues[i].l = va_arg(args, long); break; case ATYPE_LONGLONG:
argvalues[i].ll = va_arg(args, longlong); break; case ATYPE_DOUBLE:
argvalues[i].d = va_arg(args, double); break; case ATYPE_CHARPTR:
argvalues[i].cptr = va_arg(args, char *); break;
}
}
returntrue;
}
staticvoid
fmtstr(constchar *value, int leftjust, int minlen, int maxwidth, int pointflag, PrintfTarget *target)
{ int padlen,
vallen; /* amount to pad */
staticvoid
fmtptr(constvoid *value, PrintfTarget *target)
{ int vallen; char convert[64];
/* we rely on regular C library's snprintf to do the basic conversion */
vallen = snprintf(convert, sizeof(convert), "%p", value); if (vallen < 0)
target->failed = true; else
dostr(convert, vallen, target);
}
staticvoid
fmtint(longlong value, char type, int forcesign, int leftjust, int minlen, int zpad, int precision, int pointflag,
PrintfTarget *target)
{ unsignedlonglong uvalue; int base; int dosign; constchar *cvt = "0123456789abcdef"; int signvalue = 0; char convert[64]; int vallen = 0; int padlen; /* amount to pad */ int zeropad; /* extra leading zeroes */
staticvoid
fmtfloat(double value, char type, int forcesign, int leftjust, int minlen, int zpad, int precision, int pointflag,
PrintfTarget *target)
{ int signvalue = 0; int prec; int vallen; char fmt[8]; char convert[1024]; int zeropadlen = 0; /* amount to pad with zeroes */ int padlen; /* amount to pad with spaces */
if (zeropadlen > 0)
{ /* If 'e' or 'E' format, inject zeroes before the exponent */ char *epos = strrchr(convert, 'e');
if (!epos)
epos = strrchr(convert, 'E'); if (epos)
{ /* pad before exponent */
dostr(convert, epos - convert, target);
dopr_outchmulti('0', zeropadlen, target);
dostr(epos, vallen - (epos - convert), target);
} else
{ /* no exponent, pad after the digits */
dostr(convert, vallen, target);
dopr_outchmulti('0', zeropadlen, target);
}
} else
{ /* no zero padding, just emit the number as-is */
dostr(convert, vallen, target);
}
trailing_pad(padlen, target); return;
fail:
target->failed = true;
}
/* *Nonstandardentrypointtoprintadoublevalueefficiently. * *Thisisapproximatelyequivalenttostrfromd(),buthasanAPImore *adaptedtowhatfloat8out()wants.Thebehaviorislikesnprintf() *withaformatof"%.ng",wherenisthespecifiedprecision. *However,thetargetbuffermustbenonempty(i.e.count>0),and *theprecisionissilentlyboundedtoasanerange.
*/ int
pg_strfromd(char *str, size_t count, int precision, double value)
{
PrintfTarget target; int signvalue = 0; int vallen; char fmt[8]; char convert[64];
/* Set up the target like pg_snprintf, but require nonempty buffer */
Assert(count > 0);
target.bufstart = target.bufptr = str;
target.bufend = str + count - 1;
target.stream = NULL;
target.nchars = 0;
target.failed = false;
staticvoid
dostr(constchar *str, int slen, PrintfTarget *target)
{ /* fast path for common case of slen == 1 */ if (slen == 1)
{
dopr_outch(*str, target); return;
}
while (slen > 0)
{ int avail;
if (target->bufend != NULL)
avail = target->bufend - target->bufptr; else
avail = slen; if (avail <= 0)
{ /* buffer full, can we dump to stream? */ if (target->stream == NULL)
{
target->nchars += slen; /* no, lose the data */ return;
}
flushbuffer(target); continue;
}
avail = Min(avail, slen);
memmove(target->bufptr, str, avail);
target->bufptr += avail;
str += avail;
slen -= avail;
}
}
staticvoid
dopr_outch(int c, PrintfTarget *target)
{ if (target->bufend != NULL && target->bufptr >= target->bufend)
{ /* buffer full, can we dump to stream? */ if (target->stream == NULL)
{
target->nchars++; /* no, lose the data */ return;
}
flushbuffer(target);
}
*(target->bufptr++) = c;
}
staticvoid
dopr_outchmulti(int c, int slen, PrintfTarget *target)
{ /* fast path for common case of slen == 1 */ if (slen == 1)
{
dopr_outch(c, target); return;
}
while (slen > 0)
{ int avail;
if (target->bufend != NULL)
avail = target->bufend - target->bufptr; else
avail = slen; if (avail <= 0)
{ /* buffer full, can we dump to stream? */ if (target->stream == NULL)
{
target->nchars += slen; /* no, lose the data */ return;
}
flushbuffer(target); continue;
}
avail = Min(avail, slen);
memset(target->bufptr, c, avail);
target->bufptr += avail;
slen -= avail;
}
}
staticint
adjust_sign(int is_negative, int forcesign, int *signvalue)
{ if (is_negative)
{
*signvalue = '-'; returntrue;
} elseif (forcesign)
*signvalue = '+'; returnfalse;
}
staticint
compute_padlen(int minlen, int vallen, int leftjust)
{ int padlen;
padlen = minlen - vallen; if (padlen < 0)
padlen = 0; if (leftjust)
padlen = -padlen; return padlen;
}
staticvoid
leading_pad(int zpad, int signvalue, int *padlen, PrintfTarget *target)
{ int maxpad;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.