libstdio: sync bits of vfprintf from APE

* Add the %ll length modifier,
* Convert nil to "<nil>" under %s (not in APE),
* Cast void* to uintptr under %p,
* Use "0x" hex prefix under %p,
* Fix manual page mentions of %P to %p,
* Fix empty result for fp conversions,
* Fix zero padding of left-aligned fp conversions,
* Remove deprecated #pragma ref uses.

Most of these were introduced in APE prior to 9front.

I've omitted the %z conversion specifier since Plan 9 code
rarely uses the usize type. This may need to be added later
for the benefit of native ports of alien code.
front
kvik 2021-02-19 23:04:09 +01:00
parent 1ce6f0f2ab
commit bc1cc79225
2 changed files with 56 additions and 16 deletions

View File

@ -200,6 +200,22 @@ or
.B long .B long
argument; argument;
an optional an optional
.B ll
specifying that a following
.BR d ,
.BR i ,
.BR o ,
.BR u ,
.BR x ,
or
.B X
conversion character applies to a
.B long long
or
.B unsigned
.B long long
argument;
an optional
.B l .B l
specifying that a following specifying that a following
.B n .B n
@ -207,6 +223,14 @@ conversion specifier applies to a pointer to a
.B long .B long
.B int .B int
argument; argument;
an optional
.B ll
specifying that a following
.B n
conversion specifier applies to a pointer to a
.B long long
.B int
argument;
or an optional or an optional
.B L .B L
specifying that a following specifying that a following
@ -222,6 +246,7 @@ argument.
If an If an
.BR h , .BR h ,
.BR l , .BR l ,
.BR ll ,
or or
.B L .B L
appears with any other conversion specifier, the behavior is undefined. appears with any other conversion specifier, the behavior is undefined.
@ -459,7 +484,7 @@ zero
value for value for
the argument yields undefined results. the argument yields undefined results.
.TP .TP
.B P .B p
The The
.B void* .B void*
argument is printed in an implementation-defined way (for Plan 9: argument is printed in an implementation-defined way (for Plan 9:
@ -487,7 +512,7 @@ If any argument is, or points to, a union or an aggregate
conversion, or a pointer cast to be a pointer to conversion, or a pointer cast to be a pointer to
.B void .B void
using using
.B %P .B %p
conversion), the behavior is undefined. conversion), the behavior is undefined.
.PP .PP
In no case does a nonexistent or small field width cause truncation In no case does a nonexistent or small field width cause truncation

View File

@ -17,6 +17,7 @@
#define LONG 64 /* 'l' convert a long integer */ #define LONG 64 /* 'l' convert a long integer */
#define LDBL 128 /* 'L' convert a long double */ #define LDBL 128 /* 'L' convert a long double */
#define PTR 256 /* convert a void * (%p) */ #define PTR 256 /* convert a void * (%p) */
#define VLONG 512 /* 'll' convert a long long integer */
static int lflag[] = { /* leading flags */ static int lflag[] = { /* leading flags */
0, 0, 0, 0, 0, 0, 0, 0, /* ^@ ^A ^B ^C ^D ^E ^F ^G */ 0, 0, 0, 0, 0, 0, 0, 0, /* ^@ ^A ^B ^C ^D ^E ^F ^G */
@ -148,7 +149,7 @@ QLock _stdiolk;
int int
vfprintf(FILE *f, const char *s, va_list args) vfprintf(FILE *f, const char *s, va_list args)
{ {
int flags, width, precision; int tfl, flags, width, precision;
qlock(&_stdiolk); qlock(&_stdiolk);
@ -187,7 +188,15 @@ vfprintf(FILE *f, const char *s, va_list args)
} }
else else
precision = -1; precision = -1;
while(tflag[*s&_IO_CHMASK]) flags |= tflag[*s++&_IO_CHMASK];
while(tfl = tflag[*s&_IO_CHMASK]){
if(tfl == LONG && (flags & LONG)){
flags &= ~LONG;
tfl = VLONG;
}
flags |= tfl;
s++;
}
if(ocvt[*s]) nprint += (*ocvt[*s++])(f, &args, flags, width, precision); if(ocvt[*s]) nprint += (*ocvt[*s++])(f, &args, flags, width, precision);
else if(*s){ else if(*s){
putc(*s++, f); putc(*s++, f);
@ -208,9 +217,8 @@ vfprintf(FILE *f, const char *s, va_list args)
} }
static int static int
ocvt_c(FILE *f, va_list *args, int flags, int width, int precision) ocvt_c(FILE *f, va_list *args, int flags, int width, int)
{ {
#pragma ref precision
int i; int i;
if(!(flags&LEFT)) for(i=1; i<width; i++) putc(' ', f); if(!(flags&LEFT)) for(i=1; i<width; i++) putc(' ', f);
@ -226,6 +234,8 @@ ocvt_s(FILE *f, va_list *args, int flags, int width, int precision)
char *s; char *s;
s = va_arg(*args, char *); s = va_arg(*args, char *);
if(!s)
s = "<nil>";
if(!(flags&LEFT)){ if(!(flags&LEFT)){
if(precision >= 0) if(precision >= 0)
for(i=0; i!=precision && s[i]; i++); for(i=0; i!=precision && s[i]; i++);
@ -257,15 +267,14 @@ ocvt_s(FILE *f, va_list *args, int flags, int width, int precision)
} }
static int static int
ocvt_n(FILE *f, va_list *args, int flags, int width, int precision) ocvt_n(FILE *, va_list *args, int flags, int, int)
{ {
#pragma ref f
#pragma ref width
#pragma ref precision
if(flags&SHORT) if(flags&SHORT)
*va_arg(*args, short *) = nprint; *va_arg(*args, short *) = nprint;
else if(flags&LONG) else if(flags&LONG)
*va_arg(*args, long *) = nprint; *va_arg(*args, long *) = nprint;
else if(flags&VLONG)
*va_arg(*args, long long*) = nprint;
else else
*va_arg(*args, int *) = nprint; *va_arg(*args, int *) = nprint;
return 0; return 0;
@ -288,14 +297,15 @@ ocvt_fixed(FILE *f, va_list *args, int flags, int width, int precision,
char digits[128]; /* no reasonable machine will ever overflow this */ char digits[128]; /* no reasonable machine will ever overflow this */
char *sign; char *sign;
char *dp; char *dp;
long snum; long long snum;
unsigned long num; unsigned long long num;
int nout, npad, nlzero; int nout, npad, nlzero;
if(sgned){ if(sgned){
if(flags&PTR) snum = (long)va_arg(*args, void *); if(flags&PTR) snum = (uintptr)va_arg(*args, void *);
else if(flags&SHORT) snum = va_arg(*args, short); else if(flags&SHORT) snum = va_arg(*args, short);
else if(flags&LONG) snum = va_arg(*args, long); else if(flags&LONG) snum = va_arg(*args, long);
else if(flags&VLONG) snum = va_arg(*args, long long);
else snum = va_arg(*args, int); else snum = va_arg(*args, int);
if(snum < 0){ if(snum < 0){
sign = "-"; sign = "-";
@ -308,9 +318,10 @@ ocvt_fixed(FILE *f, va_list *args, int flags, int width, int precision,
} }
} else { } else {
sign = ""; sign = "";
if(flags&PTR) num = (long)va_arg(*args, void *); if(flags&PTR) num = (uintptr)va_arg(*args, void *);
else if(flags&SHORT) num = va_arg(*args, unsigned short); else if(flags&SHORT) num = va_arg(*args, unsigned short);
else if(flags&LONG) num = va_arg(*args, unsigned long); else if(flags&LONG) num = va_arg(*args, unsigned long);
else if(flags&VLONG) num = va_arg(*args, unsigned long long);
else num = va_arg(*args, unsigned int); else num = va_arg(*args, unsigned int);
} }
if(num == 0) prefix = ""; if(num == 0) prefix = "";
@ -391,7 +402,7 @@ static int
ocvt_p(FILE *f, va_list *args, int flags, int width, int precision) ocvt_p(FILE *f, va_list *args, int flags, int width, int precision)
{ {
return ocvt_fixed(f, args, flags|PTR|ALT, width, precision, 16, 0, return ocvt_fixed(f, args, flags|PTR|ALT, width, precision, 16, 0,
"0123456789ABCDEF", "0X"); "0123456789ABCDEF", "0x");
} }
static int static int
@ -495,6 +506,10 @@ ocvt_flt(FILE *f, va_list *args, int flags, int width, int precision, char afmt)
fmt = 'f'; fmt = 'f';
} }
ndig = edigits-digits; ndig = edigits-digits;
if(ndig == 0) {
ndig = 1;
digits = "0";
}
if((afmt=='g' || afmt=='G') && !(flags&ALT)){ /* knock off trailing zeros */ if((afmt=='g' || afmt=='G') && !(flags&ALT)){ /* knock off trailing zeros */
if(fmt == 'f'){ if(fmt == 'f'){
if(precision+exponent > ndig) { if(precision+exponent > ndig) {
@ -527,7 +542,7 @@ ocvt_flt(FILE *f, va_list *args, int flags, int width, int precision, char afmt)
if(sign) putc('-', f); if(sign) putc('-', f);
else if(flags&SIGN) putc('+', f); else if(flags&SIGN) putc('+', f);
else if(flags&SPACE) putc(' ', f); else if(flags&SPACE) putc(' ', f);
if(flags&ZPAD) if((flags&ZPAD) && !(flags&LEFT))
while(nout < width){ while(nout < width){
putc('0', f); putc('0', f);
nout++; nout++;