683 lines
15 KiB
C
683 lines
15 KiB
C
/* _ v f p r i n t f */
|
|
|
|
/* This function performs all the formatted printing. Floating point
|
|
* requests are forwarded to lower level floating point conversion
|
|
* functions. The function must not drag in all of the stdio library
|
|
* so that sprintf() can be used by programs which don't necessarily
|
|
* want the rest of stdio.
|
|
*/
|
|
|
|
#include "stdiolib.h"
|
|
#include <ctype.h>
|
|
|
|
/*LINTLIBRARY*/
|
|
|
|
/* Number to string conversion
|
|
*
|
|
* Separate routines are provided to convert numbers from binary to
|
|
* string representations for each base. Furthermore, long to int
|
|
* front end functions are provided in order to improve performance
|
|
* of long conversions.
|
|
*/
|
|
|
|
/* These definitions provide the masks necessary to convert longs
|
|
* where longs are wider than the natural word size. The %ld format
|
|
* requires the largest power of ten that will fit into an integer.
|
|
* For an integer of N bits, highest power of ten that will fit in
|
|
* N.log_10 2.
|
|
*/
|
|
|
|
#if LONG_MAX != INT_MAX
|
|
# define UINTBITS (CHAR_BIT * sizeof(unsigned int))
|
|
# define HEXSHIFT (UINTBITS/4*4)
|
|
# define HEXMASK ((unsigned int) ((1L << HEXSHIFT) - 1))
|
|
# define HEXDIGITS (UINTBITS/4)
|
|
# define OCTSHIFT (UINTBITS/3*3)
|
|
# define OCTMASK ((unsigned int) ((1L << OCTSHIFT) - 1))
|
|
# define OCTDIGITS (UINTBITS/3)
|
|
# define DECDIGITS (UINTBITS * 301 / 1000)
|
|
#endif
|
|
|
|
/* Radix descriptor table entry */
|
|
|
|
typedef struct radix {
|
|
char *(*utoa) P((unsigned int, char *, char *));
|
|
/* int to string function */
|
|
#if LONG_MAX != INT_MAX
|
|
char *(*ultoa) P((unsigned long, char *, struct radix *));
|
|
/* long to string function */
|
|
int lshift; /* bit shift */
|
|
unsigned int lmask; /* bit mask */
|
|
int ldigits; /* digits per section */
|
|
#endif
|
|
char *conv; /* conversion table */
|
|
} RADIX;
|
|
|
|
/* Function prototypes for unsigned and unsigned long convertors */
|
|
|
|
typedef char * (*utof) P((unsigned int, char *, char *));
|
|
typedef char * (*ultof) P((unsigned int, char *, RADIX *));
|
|
|
|
/* unsigned int to string convertors */
|
|
|
|
static char *__utod F3(register unsigned int, n,
|
|
register char *, p,
|
|
char *, conv)
|
|
|
|
{
|
|
unsigned int q;
|
|
|
|
do {
|
|
q = n / 10;
|
|
*--p = (n - q*10) + '0';
|
|
} while ((n = q) != 0);
|
|
return p;
|
|
}
|
|
|
|
static char *__utoo F3(register unsigned int, n,
|
|
register char *, p,
|
|
char *, conv)
|
|
|
|
{
|
|
do {
|
|
*--p = (n & 0x7) + '0';
|
|
} while ((n >>= 3) != 0);
|
|
return p;
|
|
}
|
|
|
|
static char *__utox F3(register unsigned int, n,
|
|
register char *, p,
|
|
char *, conv)
|
|
|
|
{
|
|
do {
|
|
*--p = conv[n & 0xf];
|
|
} while ((n >>= 4) != 0);
|
|
return p;
|
|
}
|
|
|
|
/* unsigned long to string convertors */
|
|
|
|
#if LONG_MAX != INT_MAX
|
|
static char *__ultod F3(unsigned long, n, char *, p, RADIX *, r)
|
|
|
|
{
|
|
unsigned long q;
|
|
unsigned int d;
|
|
char *t;
|
|
int i;
|
|
|
|
ASSERT(DECDIGITS <= __Mipow10);
|
|
|
|
for (;;) {
|
|
q = n / __ipow10[DECDIGITS];
|
|
d = n - q * __ipow10[DECDIGITS];
|
|
t = (*r->utoa)(d, p, NULL);
|
|
if ((n = q) == 0)
|
|
break;
|
|
for (i = DECDIGITS - (p - t); i--; )
|
|
*--t = '0';
|
|
p = t;
|
|
}
|
|
return t;
|
|
}
|
|
|
|
static char *__ultob F3(unsigned long, n, char *, p, RADIX *, r)
|
|
|
|
{
|
|
int i;
|
|
char *t;
|
|
|
|
for (;;) {
|
|
t = (*r->utoa)((unsigned int) n & r->lmask, p, r->conv);
|
|
if ((n >>= r->lshift) == 0)
|
|
break;
|
|
for (i = r->ldigits - (p - t); i--; )
|
|
*--t = '0';
|
|
p = t;
|
|
}
|
|
return t;
|
|
}
|
|
#endif
|
|
|
|
/* Digit to character conversion table */
|
|
|
|
static char __lconv[] = "0123456789abcdef";
|
|
static char __uconv[] = "0123456789ABCDEF";
|
|
|
|
/* Entries in radix descriptor table */
|
|
|
|
#define N_RADIX (sizeof(__radix)/sizeof(__radix[0]))
|
|
#define R_DECIMAL 0
|
|
#define R_HEXL 1
|
|
#define R_HEXU 2
|
|
#define R_OCTAL 3
|
|
|
|
/* Radix descriptor table */
|
|
|
|
#if LONG_MAX != INT_MAX
|
|
#define LONG(ultoa,lshift,lmask,ldigits) (ultoa),(lshift),(lmask),(ldigits),
|
|
#else
|
|
#define LONG(ultoa,lshift,lmask,ldigits)
|
|
#endif
|
|
|
|
static RADIX __radix[] = {
|
|
{__utod, LONG(__ultod, 0, 0, 0) NULL}, /* %d %u */
|
|
{__utox, LONG(__ultob, HEXSHIFT, HEXMASK, HEXDIGITS) __lconv},/* %x */
|
|
{__utox, LONG(__ultob, HEXSHIFT, HEXMASK, HEXDIGITS) __uconv},/* %X */
|
|
{__utoo, LONG(__ultob, OCTSHIFT, OCTMASK, OCTDIGITS) NULL}, /* %o */
|
|
};
|
|
|
|
/* Formatted component vector print
|
|
*
|
|
* This function prints component vectors of the output string.
|
|
*/
|
|
|
|
static void __printv F3(register FILE *, fp, int, vc, register FV *, vp)
|
|
|
|
{
|
|
__stdiobuf_t *wp; /* output buffer pointer */
|
|
__stdiobuf_t *p; /* buffer pointer */
|
|
int pad; /* padding only */
|
|
__stdiosize_t wb; /* bytes to write */
|
|
__stdiosize_t wf; /* free bytes in buffer */
|
|
__stdiosize_t len; /* length of string */
|
|
|
|
for (len = 0; ;) {
|
|
|
|
/* Gauge the amount of free space in the stream buffer */
|
|
if (! TESTFLAG(fp, _IONBF))
|
|
wf = UNUSEDINWRITEBUFFER(fp);
|
|
else {
|
|
fp->__wptr = fp->__wend = fp->__base = &fp->__buf;
|
|
wf = 0;
|
|
}
|
|
wp = GETWRITEPTR(fp);
|
|
|
|
for (;;) {
|
|
if ((wb = len) != 0 && wf != 0) {
|
|
|
|
if (wb > wf)
|
|
wb = wf;
|
|
|
|
wf -= wb;
|
|
len -= wb;
|
|
|
|
if (pad != 0)
|
|
MEMSET((char *) wp, *p, (size_t) wb);
|
|
else {
|
|
MEMCPY((char *) wp, (char *) p, (size_t) wb);
|
|
p += wb;
|
|
}
|
|
|
|
wp += wb;
|
|
}
|
|
|
|
/* Determine the nature and size of the next string to write */
|
|
if (len == 0) {
|
|
if (vc == 0) {
|
|
SETWRITEPTR(fp, wp);
|
|
return;
|
|
}
|
|
|
|
pad = vp->att & FV_F_PADDING;
|
|
len = vp->len;
|
|
p = (__stdiobuf_t *) vp->arg;
|
|
vc--;
|
|
vp++;
|
|
continue;
|
|
}
|
|
|
|
/* Flush a filled stream buffer */
|
|
if (TESTFLAG(fp, _IONBF)) {
|
|
fp->__base = p;
|
|
if (pad != 0 && wb > PWRITEAHEAD)
|
|
wb = PWRITEAHEAD;
|
|
len -= wb;
|
|
wp = p + wb;
|
|
}
|
|
SETWRITEPTR(fp, wp);
|
|
(void) FFLUSH(fp);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Filler strings */
|
|
|
|
#if PWRITEAHEAD != 4
|
|
<< Print buffer write ahead assumed to be 4 >>
|
|
#else
|
|
char __zfill[PWRITEAHEAD] = { /* zero fill */
|
|
'0', '0', '0', '0' };
|
|
static char __bfill[PWRITEAHEAD] = { /* blank fill */
|
|
' ', ' ', ' ', ' ' };
|
|
#endif
|
|
|
|
/* Format indicator */
|
|
|
|
#if 0 < '%'
|
|
# define FMTCH(x) ( (x) <= '%' )
|
|
#else
|
|
# define FMTCH(x) ( (x) >= '%' )
|
|
#endif
|
|
|
|
int __vfprintf F3(FILE *, fp, CONST char *, fmt, VA_LIST, args)
|
|
|
|
{
|
|
register __stdiobuf_t *wp; /* direct write pointer */
|
|
register __stdiobuf_t *sp; /* format string pointer */
|
|
register __stdiobuf_t *we; /* end of output buffer */
|
|
__stdiobuf_t *pb; /* line buffered scan point */
|
|
__stdiobuf_t *sb; /* base of this format */
|
|
|
|
int c; /* conversion temporary */
|
|
|
|
char *p, *q; /* pointers into workspace */
|
|
|
|
int flag; /* flags */
|
|
|
|
FV leftfill; /* left fill */
|
|
|
|
__stdiosize_t bytes; /* bytes output */
|
|
__stdiosize_t width; /* field width */
|
|
__stdiosize_t precision; /* precision */
|
|
__stdiosize_t length; /* raw length of output */
|
|
|
|
char sign; /* conversion is signed */
|
|
char negative; /* number is negative */
|
|
long vl; /* conversion temporary */
|
|
RADIX *radix; /* radix descriptor */
|
|
int vi; /* conversion temporary */
|
|
|
|
int fvc; /* vector count */
|
|
int fvx; /* vector index */
|
|
FV *fvp; /* vector scanner */
|
|
FV fv[FV_ARGS]; /* formatted vectors */
|
|
|
|
char buf[PBUFFERSIZE]; /* workspace */
|
|
|
|
if (CHECKWRITE(fp))
|
|
return 0;
|
|
|
|
/* Initialise once for buffered streams */
|
|
fv[FV_FMTPREFIX].att = FV_F_VECTOR;
|
|
fv[FV_FMTPREFIX].len = 0;
|
|
|
|
/* Buffer start for line buffered streams */
|
|
pb = GETWRITEPTR(fp);
|
|
|
|
bytes = 0;
|
|
|
|
for (sp = (__stdiobuf_t *) fmt; ;) {
|
|
|
|
/* Scan for format specifier */
|
|
sb = sp;
|
|
if (TESTFLAG(fp, _IONBF)) {
|
|
fv[FV_FMTPREFIX].arg = (char *) sb;
|
|
if ((sp = strchr((char *) sb, '%')) != NULL)
|
|
fv[FV_FMTPREFIX].len = sp - sb;
|
|
else {
|
|
length = strlen((char *) sb);
|
|
bytes += length;
|
|
sb = sp = "";
|
|
fv[FV_FMTPREFIX].len = length;
|
|
__printv(fp, 1, &fv[0]);
|
|
}
|
|
}
|
|
else {
|
|
for (;;) {
|
|
|
|
wp = GETWRITEPTR(fp);
|
|
we = GETWRITELIMIT(fp);
|
|
|
|
if (BUFFERSIZE(fp) >= PWRITEAHEAD) {
|
|
we -= PWRITEAHEAD;
|
|
while (wp < we) {
|
|
if (FMTCH(wp[0] = sp[0]) && (wp[0] == 0 || wp[0] == '%'))
|
|
goto Format0;
|
|
if (FMTCH(wp[1] = sp[1]) && (wp[1] == 0 || wp[1] == '%'))
|
|
goto Format1;
|
|
if (FMTCH(wp[2] = sp[2]) && (wp[2] == 0 || wp[2] == '%'))
|
|
goto Format2;
|
|
if (FMTCH(wp[3] = sp[3]) && (wp[3] == 0 || wp[3] == '%'))
|
|
goto Format3;
|
|
sp += PWRITEAHEAD;
|
|
wp += PWRITEAHEAD;
|
|
}
|
|
we += PWRITEAHEAD;
|
|
}
|
|
for (; wp < we; wp++, sp++) {
|
|
if (FMTCH(wp[0] = sp[0]) && (wp[0] == 0 || wp[0] == '%'))
|
|
goto Format0;
|
|
}
|
|
SETWRITEPTR(fp, wp);
|
|
FFLUSH(fp);
|
|
}
|
|
|
|
Format3: wp += 3; sp += 3; goto Format0;
|
|
Format2: wp += 2; sp += 2; goto Format0;
|
|
Format1: wp += 1; sp += 1; goto Format0;
|
|
Format0:
|
|
|
|
SETWRITEPTR(fp, wp);
|
|
}
|
|
|
|
/* Format or end of format found */
|
|
bytes += sp - sb;
|
|
|
|
if (*sp == 0)
|
|
break;
|
|
sp++;
|
|
|
|
/* Initialise conversion variables */
|
|
p = q = &buf[sizeof(buf)-1];
|
|
|
|
flag = 0;
|
|
leftfill.arg = __bfill;
|
|
width = 0;
|
|
|
|
/* Switch through all the format options */
|
|
Parse_again:
|
|
switch (c = *sp++) {
|
|
|
|
case '-': flag |= F_LEFTJUSTIFY; goto Parse_again;
|
|
case '+': flag |= F_SHOWSIGN; goto Parse_again;
|
|
case ' ': flag |= F_BLANKPREFIX; goto Parse_again;
|
|
case '#': flag |= F_ALTERNATE; goto Parse_again;
|
|
|
|
/* Check for field width and precision */
|
|
case '*':
|
|
if ((c = VA_ARG(args, int)) < 0) {
|
|
flag |= F_LEFTJUSTIFY;
|
|
c = -c;
|
|
}
|
|
width = c;
|
|
c = *sp++;
|
|
goto Precision;
|
|
|
|
/* Zero fill and field width */
|
|
case '0':
|
|
leftfill.arg = __zfill;
|
|
c = *sp++;
|
|
|
|
case '1': case '2': case '3': case '4': case '5':
|
|
case '6': case '7': case '8': case '9':
|
|
for (; c >= '0' && c <= '9'; c = *sp++) {
|
|
width *= 10;
|
|
width += (c - '0');
|
|
}
|
|
|
|
case '.':
|
|
Precision:
|
|
if (c == '.') {
|
|
c = *sp++;
|
|
if (c == '*') {
|
|
if ((c = VA_ARG(args, int)) >= 0) {
|
|
flag |= F_PRECISION;
|
|
precision = c;
|
|
}
|
|
sp++;
|
|
}
|
|
else if (c >= '0' && c <= '9') {
|
|
flag |= F_PRECISION;
|
|
precision = 0;
|
|
for (; c >= '0' && c <= '9'; c = *sp++) {
|
|
precision *= 10;
|
|
precision += (c - '0');
|
|
}
|
|
}
|
|
}
|
|
sp--;
|
|
goto Parse_again;
|
|
|
|
/* Short indication */
|
|
case 'h':
|
|
flag = (flag & ~(F_SHORT | F_LONG | F_LONGDOUBLE)) | F_SHORT;
|
|
goto Parse_again;
|
|
|
|
/* Long indication */
|
|
case 'l':
|
|
flag = (flag & ~(F_SHORT | F_LONG | F_LONGDOUBLE)) | F_LONG;
|
|
goto Parse_again;
|
|
|
|
/* Long double indication */
|
|
case 'L':
|
|
flag = (flag & ~(F_SHORT | F_LONG | F_LONGDOUBLE)) | F_LONGDOUBLE;
|
|
goto Parse_again;
|
|
|
|
/* Number of bytes output */
|
|
case 'n':
|
|
*(VA_ARG(args, int *)) = bytes;
|
|
continue;
|
|
|
|
/* Pointer */
|
|
case 'p':
|
|
flag = (flag & ~(F_SHORT | F_LONG | F_LONGDOUBLE)) |
|
|
F_LONG * (sizeof(void *) == sizeof(long));
|
|
sign = 0;
|
|
radix = &__radix[R_HEXL];
|
|
goto oxud;
|
|
|
|
/* Integer conversions */
|
|
case 'X':
|
|
flag |= F_0X;
|
|
sign = 0;
|
|
radix = &__radix[R_HEXU];
|
|
goto oxud;
|
|
|
|
case 'x':
|
|
sign = 0;
|
|
radix = &__radix[R_HEXL];
|
|
goto oxud;
|
|
|
|
case 'u':
|
|
sign = 0;
|
|
radix = &__radix[R_DECIMAL];
|
|
goto oxud;
|
|
|
|
case 'o':
|
|
sign = 0;
|
|
radix = &__radix[R_OCTAL];
|
|
goto oxud;
|
|
|
|
case 'i':
|
|
case 'd':
|
|
sign = 1;
|
|
radix = &__radix[R_DECIMAL];
|
|
|
|
oxud:
|
|
if ((flag & F_LONG) != 0) {
|
|
if (sign) vl = VA_ARG(args, long);
|
|
else vl = VA_ARG(args, unsigned long);
|
|
if ((negative = sign && vl < 0) != 0)
|
|
vl = -vl;
|
|
#if LONG_MAX != INT_MAX
|
|
q = (*radix->ultoa)((unsigned long) vl, q, radix);
|
|
#else
|
|
q = (*radix->utoa)((unsigned int) vl, q, radix->conv);
|
|
#endif
|
|
}
|
|
else {
|
|
if ((flag & F_SHORT) != 0)
|
|
if (sign) vi = (int) VA_ARG(args, short);
|
|
else vi = (int) VA_ARG(args, unsigned short);
|
|
else
|
|
if (sign) vi = (int) VA_ARG(args, int);
|
|
else vi = (int) VA_ARG(args, unsigned);
|
|
if ((negative = (sign && vi < 0)) != 0)
|
|
vi = -vi;
|
|
q = (*radix->utoa)((unsigned int) vi, q, radix->conv);
|
|
}
|
|
|
|
if ((flag & F_PRECISION) != 0 && precision > width) {
|
|
width = precision;
|
|
leftfill.arg = __zfill;
|
|
}
|
|
|
|
fv[FV_INTINT].att = FV_F_VECTOR;
|
|
fv[FV_INTINT].len = p - q;
|
|
fv[FV_INTINT].arg = q;
|
|
fv[FV_INTSIGN].att = FV_F_VECTOR;
|
|
fv[FV_INTSIGN].len = 0;
|
|
fvc = FV_INTARGS;
|
|
|
|
if (negative) {
|
|
fv[FV_INTSIGN].len++;
|
|
*--q = '-';
|
|
}
|
|
else if (sign) {
|
|
if ((flag & F_SHOWSIGN) != 0) {
|
|
fv[FV_INTSIGN].len++;
|
|
*--q = '+';
|
|
}
|
|
else if ((flag & F_BLANKPREFIX) != 0) {
|
|
fv[FV_INTSIGN].len++;
|
|
*--q = ' ';
|
|
}
|
|
}
|
|
if ((flag & F_ALTERNATE) != 0) {
|
|
if (radix == &__radix[R_OCTAL]) {
|
|
fv[FV_INTSIGN].len++;
|
|
*--q = '0';
|
|
}
|
|
else if (radix == &__radix[R_HEXL] || radix == &__radix[R_HEXU]) {
|
|
fv[FV_INTSIGN].len += 2;
|
|
*--q = (flag & F_0X) != 0 ? 'X' : 'x';
|
|
*--q = '0';
|
|
}
|
|
}
|
|
fv[FV_INTSIGN].arg = q;
|
|
length = p - q;
|
|
break;
|
|
|
|
/* Floating point formats */
|
|
case 'f':
|
|
flag |= F_FPFORMATF;
|
|
goto Fconvert;
|
|
|
|
case 'E':
|
|
flag |= F_FPCAPITAL;
|
|
case 'e':
|
|
flag |= F_FPFORMATE;
|
|
goto Fconvert;
|
|
|
|
case 'G':
|
|
flag |= F_FPCAPITAL;
|
|
case 'g':
|
|
flag |= F_FPFORMATG;
|
|
Fconvert:
|
|
if ((flag & F_PRECISION) == 0) precision = 6;
|
|
fvc = FV_FMTARGS
|
|
+ __cvt(&length, &fv[FV_FMTARGS], buf, &args, precision, flag);
|
|
ASSERT(fvc <= FV_ARGS);
|
|
break;
|
|
|
|
/* Single character format */
|
|
case 'c':
|
|
*--q = VA_ARG(args, int);
|
|
goto Simple_vector;
|
|
|
|
/* String format */
|
|
case 's':
|
|
if ((q = VA_ARG(args, char *)) == NULL)
|
|
q = "(null)";
|
|
if ((flag & F_PRECISION) == 0)
|
|
p = q + strlen(q);
|
|
else {
|
|
if ((p = (char *) MEMCHR(q, 0, (size_t) precision)) == NULL)
|
|
p = q + precision;
|
|
}
|
|
goto Simple_vector;
|
|
|
|
/* Default just print it */
|
|
default:
|
|
*--q = sp[-1];
|
|
|
|
/* Construct a simple vector */
|
|
Simple_vector:
|
|
length = p - q;
|
|
fv[FV_INTINT].att = FV_F_VECTOR;
|
|
fv[FV_INTINT].len = length;
|
|
fv[FV_INTINT].arg = q;
|
|
fv[FV_INTSIGN].att = FV_F_VECTOR;
|
|
fv[FV_INTSIGN].len = 0;
|
|
fvc = FV_INTARGS;
|
|
break;
|
|
}
|
|
|
|
/* Start vector index */
|
|
fvx = 0;
|
|
fvp = &fv[0];
|
|
bytes += length;
|
|
|
|
/* Subtract to find padding required --- no padding */
|
|
if (width <= length) {
|
|
width = 0;
|
|
|
|
fv[FV_FMTARGS+1].len += fv[FV_FMTARGS].len;
|
|
fv[FV_FMTARGS+1].arg -= fv[FV_FMTARGS].len;
|
|
fv[FV_FMTARGS].len = 0;
|
|
}
|
|
|
|
/* Some padding required (may be right or left) */
|
|
else {
|
|
width -= length;
|
|
|
|
/* Required right justification (padding on left) */
|
|
if ((flag & F_LEFTJUSTIFY) == 0) {
|
|
|
|
/* Print format string first */
|
|
#if FV_FMTARGS != 1
|
|
<< FV_FMTARGS assumed to be 1 >>
|
|
#else
|
|
if (fvp->len > 0)
|
|
__printv(fp, FV_FMTARGS, fvp);
|
|
#endif
|
|
fvp += FV_FMTARGS;
|
|
fvx += FV_FMTARGS;
|
|
|
|
/* Check for negative and zero fill */
|
|
if (leftfill.arg == __zfill && fv[FV_FMTARGS].len != 0) {
|
|
__printv(fp, 1, &fv[FV_FMTARGS]);
|
|
fvx++;
|
|
fvp++;
|
|
}
|
|
|
|
/* Now output the rest of the padding */
|
|
bytes += width;
|
|
leftfill.att = FV_F_PADDING;
|
|
leftfill.len = width;
|
|
width = 0;
|
|
__printv(fp, 1, &leftfill);
|
|
}
|
|
}
|
|
|
|
/* Output the string proper */
|
|
__printv(fp, fvc-fvx, fvp);
|
|
|
|
/* Check for required right padding */
|
|
if (width != 0) {
|
|
bytes += width;
|
|
leftfill.att = FV_F_PADDING;
|
|
leftfill.len = width;
|
|
leftfill.arg = __bfill;
|
|
__printv(fp, 1, &leftfill);
|
|
}
|
|
}
|
|
|
|
/* Flush line buffered streams */
|
|
if (TESTFLAG(fp, _IOLBF)) {
|
|
length = bytes;
|
|
if (bytes + pb != GETWRITEPTR(fp)) {
|
|
pb = fp->__base;
|
|
length = BYTESINWRITEBUFFER(fp);
|
|
}
|
|
pb = (__stdiobuf_t *) MEMCHR(pb, '\n', (size_t) length);
|
|
if (pb != NULL)
|
|
(void) FFLUSH(fp);
|
|
}
|
|
|
|
return ferror(fp) ? EOF : bytes;
|
|
}
|