OSDN Git Service

Since Erik apparently wants def/undef vs def 1/0...
[uclinux-h8/uClibc.git] / libc / stdio / printf.c
1 /*
2  * This file based on printf.c from 'Dlibs' on the atari ST  (RdeBath)
3  *
4  * 
5  *    Dale Schumacher                         399 Beacon Ave.
6  *    (alias: Dalnefre')                      St. Paul, MN  55104
7  *    dal@syntel.UUCP                         United States of America
8  *  "It's not reality that's important, but how you perceive things."
9  */
10
11 /* Altered to use stdarg, made the core function vfnprintf.
12  * Hooked into the stdio package using 'inside information'
13  * Altered sizeof() assumptions, now assumes all integers except chars
14  * will be either
15  *  sizeof(xxx) == sizeof(long) or sizeof(xxx) == sizeof(short)
16  *
17  * -RDB
18  */
19
20 /*
21  *                    Manuel Novoa III   Dec 2000
22  *
23  * The previous vfnprintf routine was almost completely rewritten with the
24  * goal of fixing some shortcomings and reducing object size.
25  *
26  * The summary of changes:
27  *
28  * Converted print conversion specification parsing from one big switch
29  *   to a method using string tables.  This new method verifies that the
30  *   conversion flags, field width, precision, qualifier, and specifier
31  *   appear in the correct order.  Many questionable specifications were
32  *   accepted by the previous code.  This new method also resulted in a
33  *   substantial reduction in object size of about 330 bytes (20%) from
34  *   the old version (1627 bytes) on i386, even with the following
35  *   improvements.
36  *
37  *     Implemented %n specifier as required by the standards.
38  *     Implemented proper handling of precision for int types.
39  *     Implemented # for hex and pointer, fixed error for octal rep of 0.
40  *     Implemented return of -1 on stream error.
41  *
42  * Added optional support for the GNU extension %m which prints the string
43  *   corresponding the errno.
44  *
45  * Added optional support for long long ints and unsigned long long ints
46  *   using the conversion qualifiers "ll", "L", or "q" (like glibc).
47  *
48  * Added optional support for doubles in a very limited form.  None of
49  *   the formating options are obeyed.  The string returned by __dtostr
50  *   is printed directly.
51  *
52  * Converted to use my (un)signed long (long) to string routines, which are
53  * smaller than the previous functions and don't require static buffers.
54  *
55  * Other Modifications:
56  *   Modified sprintf, snprintf, vsprintf, vsnprintf to share on fake-file.
57  */
58
59 /*
60  *                    Manuel Novoa III   Jan 2000
61  *
62  * Removed fake file from *s*printf functions because of possible problems
63  *    if called recursively.  Instead, have sprintf, snprintf, and vsprintf
64  *    call vsnprintf which allocates a fake file on the stack.
65  * Removed WANT_FPUTC option.  Always use standard putc macro to avoid
66  *    problems with the fake file used by the *s*printf functions.
67  * Fixed bug parsing flags -- did not restart scan.
68  * Added function asprintf.
69  * Fixed 0-pad prefixing bug.
70  * Converted sizeof(int) == sizeof(long) tests to compile time vs run time.
71  *    This saves 112 bytes of code on i386.
72  * Fixed precision bug -- when negative set to default.
73  * Added function fnprintf to support __dtostr.
74  * Added floating point support for doubles.  Yeah!
75  * 
76  * TODO: long double support
77  */
78
79 /*****************************************************************************/
80 /*                            OPTIONS                                        */
81 /*****************************************************************************/
82 /* The optional support for long longs and doubles comes in two forms.
83  *
84  *   1) Normal (or partial for doubles) output support.  Set to 1 to turn on.
85  *      Adds about 130 bytes for doubles, about 220 bytes for long longs,
86  *      and about 275 for both to the base code size of 1163 on i386.
87  */
88
89 /* These are now set in uClibc_config.h based on Config. */
90 /*
91 #define __UCLIBC_HAS_LONG_LONG__         1
92 #define __UCLIBC_HAS_FLOATS__            1
93 */
94
95 /*   2) An error message is inserted into the stream, an arg of the
96  *      appropriate size is removed from the arglist, and processing
97  *      continues.  This is adds less code and may be useful in some
98  *      cases.  Set to 1 to turn on.  Adds about 50 bytes for doubles,
99  *      about 140 bytes for long longs, and about 175 bytes for both
100  *      to the base code size of 1163 on i386.
101  */
102
103 #define WANT_LONG_LONG_ERROR   0
104 #define WANT_FLOAT_ERROR      0
105
106 /*
107  * Set to support GNU extension of %m to print string corresponding to errno.
108  *
109  * Warning: This adds about 50 bytes (i386) to the code but it also pulls in
110  * strerror and the corresponding string table which together are about 3.8k.
111  */
112
113 #define WANT_GNU_ERRNO         0
114
115 /**************************************************************************/
116
117 #include <sys/types.h>
118 #include <fcntl.h>
119 #include <string.h>
120 #include <stdlib.h>
121 #include <limits.h>
122 #include <assert.h>
123
124 #if WANT_GNU_ERRNO
125 #include <errno.h>
126 #endif
127
128 #ifdef __STDC__
129 #include <stdarg.h>
130 #define va_strt      va_start
131 #else
132 #include <varargs.h>
133 #define va_strt(p,i) va_start(p)
134 #endif
135
136 #include "stdio.h"
137
138 extern int vfnprintf(FILE * op, size_t max_size,
139                                          register __const char *fmt, register va_list ap);
140
141 #ifdef L_printf
142 int printf(const char *fmt, ...)
143 {
144         va_list ptr;
145         int rv;
146
147         va_strt(ptr, fmt);
148         rv = vfnprintf(stdout, -1, fmt, ptr);
149         va_end(ptr);
150         return rv;
151 }
152 #endif
153
154 #ifdef L_asprintf
155 int asprintf(char **app, const char *fmt, ...)
156 {
157         va_list ptr;
158         int rv, i;
159         char *p;                                        /* unitialized warning is ok here */
160         /*
161          * First  iteration - find out size of buffer required and allocate it.
162          * Second iteration - actually produce output.
163          */
164         rv = 0;
165         for (i=0 ; i<2 ; i++) {
166                 va_strt(ptr, fmt);
167                 rv = vsnprintf(p, rv, fmt, ptr);
168                 va_end(ptr);
169
170                 if (i==0) {                             /* first time through so */
171                         p = malloc(++rv); /* allocate the buffer */
172                         *app = p;
173                         if (!p) {
174                                 return -1;
175                         }
176                 }
177         }
178         return rv;
179 }
180 #endif
181
182 #ifdef L_sprintf
183 int sprintf(char *sp, const char *fmt, ...)
184 {
185         va_list ptr;
186         int rv;
187
188         va_strt(ptr, fmt);
189         rv = vsnprintf(sp, -1, fmt, ptr);
190         va_end(ptr);
191         return rv;
192 }
193 #endif
194
195
196 #ifdef L_snprintf
197 int snprintf(char *sp, size_t size, const char *fmt, ...)
198 {
199         va_list ptr;
200         int rv;
201
202         va_strt(ptr, fmt);
203         rv = vsnprintf(sp, size, fmt, ptr);
204         va_end(ptr);
205         return rv;
206 }
207 #endif
208
209 #ifdef L_fprintf
210 int fprintf(FILE * fp, const char *fmt, ...)
211 {
212         va_list ptr;
213         int rv;
214
215         va_strt(ptr, fmt);
216         rv = vfnprintf(fp, -1, fmt, ptr);
217         va_end(ptr);
218         return rv;
219 }
220 #endif
221
222 #ifdef L_fnprintf
223 int fnprintf(FILE * fp, size_t size, const char *fmt, ...)
224 {
225         va_list ptr;
226         int rv;
227
228         va_strt(ptr, fmt);
229         rv = vfnprintf(fp, size, fmt, ptr);
230         va_end(ptr);
231         return rv;
232 }
233 #endif
234
235 #ifdef L_vprintf
236 int vprintf(const char *fmt, va_list ap)
237 {
238         return vfprintf(stdout, fmt, ap);
239 }
240 #endif
241
242 #ifdef L_vfprintf
243
244 int vfprintf(FILE * op, register __const char *fmt, register va_list ap)
245 {
246         return vfnprintf(op, -1, fmt, ap);
247 }
248
249 #endif
250
251 #ifdef L_vsprintf
252 int vsprintf(char *sp, __const char *fmt, va_list ap)
253 {
254         return vsnprintf(sp, -1, fmt, ap);
255 }
256 #endif
257
258 #ifdef L_vsnprintf
259 int vsnprintf(char *sp, size_t size, __const char *fmt, va_list ap)
260 {
261         int rv;
262         FILE f;
263
264         /*
265          * As we're only using the putc macro in vfnprintf, we don't need to
266          * initialize all FILE f's fields.
267          */
268         f.bufwrite = (char *) ((unsigned) -1);
269         f.bufpos = sp;
270         f.mode = _IOFBF;
271
272         rv = vfnprintf(&f, size, fmt, ap);
273         if (size) {                                     /* If this is going to a buffer, */
274                 *(f.bufpos) = 0;                /* don't forget to nul-terminate. */
275         }
276         return rv;
277 }
278 #endif
279
280 #ifdef L_vdprintf
281 /*
282  * Note: If fd has an associated buffered FILE, bad things happen.
283  */
284 extern int vdprintf(int fd, const char *fmt, va_list ap)
285 {
286         char buf[BUFSIZ];
287         FILE f = {buf, 0, buf+sizeof(buf), buf, buf+sizeof(buf), 0, fd, _IOFBF};
288         int rv;
289
290         rv = vfnprintf(&f, -1, fmt, ap);
291
292         if (fflush(&f)) {
293                 return -1;
294         }
295
296         return rv;
297 }
298 #endif
299
300 #ifdef L_vfnprintf
301
302 extern char *__ultostr(char *buf, unsigned long uval, int base, int uppercase);
303 extern char *__ltostr(char *buf, long val, int base, int uppercase);
304 extern char *__ulltostr(char *buf, unsigned long long uval, int base, int uppercase);
305 extern char *__lltostr(char *buf, long long val, int base, int uppercase);
306 extern int __dtostr(FILE * fp, size_t size, long double x,
307                                   char flag[], int width, int preci, char mode);
308
309 enum {
310         FLAG_PLUS = 0,
311         FLAG_MINUS_LJUSTIFY,
312         FLAG_HASH,
313         FLAG_0_PAD,
314         FLAG_SPACE,
315 };
316
317 /* layout                   01234  */
318 static const char spec[] = "+-#0 ";
319
320 #if defined(__UCLIBC_HAS_LONG_LONG__) || WANT_LONG_LONG_ERROR
321 static const char qual[] = "hlLq";
322 #else
323 static const char qual[] = "hl";
324 #endif
325
326 #if !defined(__UCLIBC_HAS_LONG_LONG__) && WANT_LONG_LONG_ERROR
327 static const char ll_err[] = "<LONG-LONG>";
328 #endif
329
330 #if !defined(__UCLIBC_HAS_FLOATS__) && WANT_FLOAT_ERROR
331 static const char dbl_err[] = "<DOUBLE>";
332 #endif
333
334 #if defined(__UCLIBC_HAS_FLOATS__) || WANT_FLOAT_ERROR
335 /* layout                     012345678901234567   */
336 static const char u_spec[] = "%nbopxXudicsfgGeEaA";
337 #else
338 /* layout                     0123456789012   */
339 static const char u_spec[] = "%nbopxXudics";
340 #endif
341
342 /* WARNING: u_spec and u_radix need to stay in agreement!!! */
343 /* u_radix[i] <-> u_spec[i+2] for unsigned entries only */
344 static const char u_radix[] = "\x02\x08\x10\x10\x10\x0a";
345
346 int vfnprintf(FILE * op, size_t max_size, const char *fmt, va_list ap)
347 {
348         int i, cnt, lval;
349         char *p;
350         const char *fmt0;
351         int buffer_mode;
352         int preci, width;
353 #define upcase i
354         int radix, dpoint /*, upcase*/;
355 #if defined(__UCLIBC_HAS_LONG_LONG__)
356         char tmp[65];
357 #else
358         char tmp[33];
359 #endif
360         char flag[sizeof(spec)];
361
362         cnt = 0;
363
364         /* This speeds things up a bit for line unbuffered */
365         buffer_mode = (op->mode & __MODE_BUF);
366         op->mode &= (~__MODE_BUF);
367
368         while (*fmt) {
369                 if (*fmt == '%') {
370                         fmt0 = fmt;                     /* save our position in case of bad format */
371                         ++fmt;
372                         width = -1;                     /* min field width */
373                         preci = -5;                     /* max string width or mininum digits */
374                         radix = 10;                     /* number base */
375                         dpoint = 0;                     /* found decimal point */
376 #if INT_MAX != LONG_MAX
377                         lval = 0;                       /* sizeof(int) != sizeof(long) */
378 #else
379                         lval = 1;                       /* sizeof(int) == sizeof(long) */
380 #endif
381
382                         tmp[1] = 0;                     /* set things up for %c -- better done here */
383
384                         /* init flags */
385                         for (p =(char *) spec ; *p ; p++) {
386                                 flag[p-spec] = '\0';
387                         }
388                         flag[FLAG_0_PAD] = ' ';
389
390                         /* process optional flags */
391                         for (p = (char *)spec ; *p ; ) {
392                                 if (*fmt == *p) {
393                                         flag[p-spec] = *fmt++;
394                                         p = (char *)spec; /* restart scan */
395                                 } else {
396                                         p++;
397                                 }
398                         }
399                         
400                         if (!flag[FLAG_PLUS]) {
401                                 flag[FLAG_PLUS] = flag[FLAG_SPACE];
402                         }
403
404                         /* process optional width and precision */
405                         do {
406                                 if (*fmt == '.') {
407                                         ++fmt;
408                                         dpoint = 1;
409                                 }
410                                 if (*fmt == '*') {      /* parameter width value */
411                                         ++fmt;
412                                         i = va_arg(ap, int);
413                                 } else {
414                                         for ( i = 0 ; (*fmt >= '0') && (*fmt <= '9') ; ++fmt ) {
415                                                 i = (i * 10) + (*fmt - '0');
416                                         }
417                                 }
418
419                                 if (dpoint) {
420                                         preci = i;
421                                         if (i<0) {
422                                                 preci = -5;
423                                         }
424                                 } else {
425                                         width = i;
426                                         if (i<0) {
427                                                 width = -i;
428                                                 flag[FLAG_MINUS_LJUSTIFY] = 1;
429                                         }
430                                 }
431                         } while ((*fmt == '.') && !dpoint );
432
433                         /* process optional qualifier */
434                         for (p = (char *) qual ; *p ; p++) {
435                                 if (*p == *fmt) {
436                                         lval = p - qual;
437                                         ++fmt;
438 #if defined(__UCLIBC_HAS_LONG_LONG__) || WANT_LONG_LONG_ERROR
439                                         if ((*p == 'l') && (*fmt == *p)) {
440                                                 ++lval;
441                                                 ++fmt;
442                                         }
443 #endif /* defined(__UCLIBC_HAS_LONG_LONG__) || WANT_LONG_LONG_ERROR */
444                                 }
445                         }
446
447 #if WANT_GNU_ERRNO
448                         if (*fmt == 'm') {
449                                 flag[FLAG_PLUS] = '\0';
450                                 flag[FLAG_0_PAD] = ' ';
451                                 p = strerror(errno);
452                                 goto print;
453                         }
454 #endif
455
456                         /* process format specifier */
457                         for (p = (char *) u_spec ; *p ; p++) {
458                                 if (*fmt != *p) continue;
459                                 if (p-u_spec < 1) {     /* print a % */
460                                         goto charout;
461                                 }
462                                 if (p-u_spec < 2) {     /* store output count in int ptr */
463                                         *(va_arg(ap, int *)) = cnt;
464                                         goto nextfmt;
465                                 }
466                                 if (p-u_spec < 8) { /* unsigned conversion */
467                                         radix = u_radix[p-u_spec-2];
468                                         upcase = ((int)'x') - *p;
469                                         if (*p == 'p') {
470                                                 lval = (sizeof(char *) == sizeof(long));
471                                                 upcase = 0;
472                                         }
473 #if defined(__UCLIBC_HAS_LONG_LONG__) || WANT_LONG_LONG_ERROR
474                                         if (lval >= 2) {
475 #if defined(__UCLIBC_HAS_LONG_LONG__)
476                                                 p = __ulltostr(tmp + sizeof(tmp) - 1,
477                                                                            va_arg(ap, unsigned long long),
478                                                                            radix, upcase);
479 #else
480                                                 (void) va_arg(ap, unsigned long long);  /* cary on */
481                                                 p = (char *) ll_err;
482 #endif /* defined(__UCLIBC_HAS_LONG_LONG__) */
483                                         } else {
484 #endif /* defined(__UCLIBC_HAS_LONG_LONG__) || WANT_LONG_LONG_ERROR */
485 #if UINT_MAX != ULONG_MAX
486                                                 /* sizeof(unsigned int) != sizeof(unsigned long) */
487                                                 p = __ultostr(tmp + sizeof(tmp) - 1, (unsigned long)
488                                                                           ((lval)
489                                                                            ? va_arg(ap, unsigned long)
490                                                                            : va_arg(ap, unsigned int)),
491                                                                           radix, upcase);
492 #else
493                                                 /* sizeof(unsigned int) == sizeof(unsigned long) */
494                                                 p = __ultostr(tmp + sizeof(tmp) - 1, (unsigned long)
495                                                                           va_arg(ap, unsigned long),
496                                                                           radix, upcase);
497 #endif
498 #if defined(__UCLIBC_HAS_LONG_LONG__) || WANT_LONG_LONG_ERROR
499                                         }
500 #endif /* defined(__UCLIBC_HAS_LONG_LONG__) || WANT_LONG_LONG_ERROR */
501                                         flag[FLAG_PLUS] = '\0'; /* meaningless for unsigned */
502                                         if (flag[FLAG_HASH] && (*p != '0')) { /* non-zero */
503                                                 if (radix == 8) {
504                                                         *--p = '0';     /* add leadding zero */
505                                                 } else if (radix != 10) { /* either 2 or 16 */
506                                                         flag[FLAG_PLUS] = '0';
507                                                         *--p = 'b';
508                                                         if (radix == 16) {
509                                                                 *p = 'x';
510                                                                 if (*fmt == 'X') {
511                                                                         *p = 'X';
512                                                                 }
513                                                         }
514                                                 }
515                                         }
516                                 } else if (p-u_spec < 10) { /* signed conversion */
517 #if defined(__UCLIBC_HAS_LONG_LONG__) || WANT_LONG_LONG_ERROR
518                                         if (lval >= 2) {
519 #if defined(__UCLIBC_HAS_LONG_LONG__)
520                                                 p = __lltostr(tmp + sizeof(tmp) - 1,
521                                                                           va_arg(ap, long long), 10, 0);
522 #else
523                                                 (void) va_arg(ap, long long); /* carry on */
524                                                 p = (char *) ll_err;
525 #endif /* defined(__UCLIBC_HAS_LONG_LONG__) */
526                                         } else {
527 #endif /* defined(__UCLIBC_HAS_LONG_LONG__) || WANT_LONG_LONG_ERROR */
528 #if INT_MAX != LONG_MAX
529                                                 /* sizeof(int) != sizeof(long) */
530                                                 p = __ltostr(tmp + sizeof(tmp) - 1, (long)
531                                                                          ((lval)
532                                                                           ? va_arg(ap, long)
533                                                                           : va_arg(ap, int)), 10, 0);
534 #else
535                                                 /* sizeof(int) == sizeof(long) */
536                                                 p = __ltostr(tmp + sizeof(tmp) - 1, (long)
537                                                                          va_arg(ap, long), 10, 0);
538 #endif
539 #if defined(__UCLIBC_HAS_LONG_LONG__) || WANT_LONG_LONG_ERROR
540                                         }
541 #endif /* defined(__UCLIBC_HAS_LONG_LONG__) || WANT_LONG_LONG_ERROR */
542                                 } else if (p-u_spec < 12) {     /* character or string */
543                                         flag[FLAG_PLUS] = '\0';
544                                         flag[FLAG_0_PAD] = ' ';
545                                         if (*p == 'c') {        /* character */
546                                                 p = tmp;
547                                                 *p = va_arg(ap, int);
548                                         } else {        /* string */
549                                                 p = va_arg(ap, char *);
550                                                 if (!p) {
551                                                         p = "(null)";
552                                                 }
553                                         }
554 #if defined(__UCLIBC_HAS_FLOATS__) || WANT_FLOAT_ERROR
555                                 } else if (p-u_spec < 27) {             /* floating point */
556 #endif /* defined(__UCLIBC_HAS_FLOATS__) || WANT_FLOAT_ERROR */
557 #if defined(__UCLIBC_HAS_FLOATS__)
558                                         if (preci < 0) {
559                                                 preci = 6;
560                                         }
561                                         cnt += __dtostr(op, 
562                                                                         (max_size > cnt ? max_size - cnt : 0),
563                                                                         (long double) ((lval > 1)
564                                                                          ? va_arg(ap, long double)
565                                                                          : va_arg(ap, double)),
566                                                                         flag, width,  preci, *fmt);
567                                         goto nextfmt;
568 #elif WANT_FLOAT_ERROR
569                                         (void) ((lval > 1) ? va_arg(ap, long double)
570                                                         : va_arg(ap, double)); /* carry on */
571                                         p = (char *) dbl_err;
572 #endif /* defined(__UCLIBC_HAS_FLOATS__) */
573                                 }
574
575 #if WANT_GNU_ERRNO
576                         print:
577 #endif
578                                 {                               /* this used to be printfield */
579                                         int len;
580
581                                         /* cheaper than strlen call */
582                                         for ( len = 0 ; p[len] ; len++ ) { }
583
584                                         if ((*p == '-')
585 #if WANT_GNU_ERRNO
586                                                 && (*fmt != 'm')
587 #endif
588                                                 && (*fmt != 's')) {
589                                                 flag[FLAG_PLUS] = *p++;
590                                                 --len;
591                                         }
592                                     if (flag[FLAG_PLUS]) {
593                                                 ++len;
594                                                 ++preci;
595                                                 if (flag[FLAG_PLUS] == '0') { /* base 16 */
596                                                         ++preci; /* account for x or X */
597                                                 }
598                                         }
599
600                                         if (preci >= 0) {
601                                                 if ((*fmt == 's')
602 #if WANT_GNU_ERRNO
603                                                 || (*fmt == 'm')
604 #endif
605                                                 ) {
606                                                         if (len > preci) {
607                                                                 len = preci;
608                                                         } else {
609                                                                 preci = len;
610                                                         }
611                                                 }
612                                                 preci -= len;
613                                                 if (preci < 0) {
614                                                         preci = 0;
615                                                 }
616                                                 width -= preci;
617                                         }
618
619                                         width -= len;
620                                         if (width < 0) {
621                                                 width = 0;
622                                         }
623
624                                         if (preci < 0) {
625                                                 preci = 0;
626                                                 if (!flag[FLAG_MINUS_LJUSTIFY]
627                                                         /* && flag[FLAG_PLUS] */
628                                                         && (flag[FLAG_0_PAD] == '0')) { 
629                                                         preci = width;
630                                                         width = 0;
631                                                 }
632                                         }
633
634                                         while (width + len + preci) {
635                                                 unsigned char ch;
636                                                 /* right padding || left padding */
637                                                 if ((!len && !preci)
638                                                         || (width && !flag[FLAG_MINUS_LJUSTIFY])) {
639                                                         ch = ' ';
640                                                         --width;
641                                                 } else if (flag[FLAG_PLUS]) {
642                                                         ch = flag[FLAG_PLUS]; /* sign */
643                                                         if (flag[FLAG_PLUS]=='0') {     /* base 16 case */
644                                                                 flag[FLAG_PLUS] = *p++; /* get the x|X */
645                                                         } else {
646                                                                 flag[FLAG_PLUS] = '\0';
647                                                         }
648                                                         --len;
649                                                 } else if (preci) {
650                                                         ch = '0';
651                                                         --preci;
652                                                 } else {
653                                                         ch = *p++; /* main field */
654                                                         --len;
655                                                 }
656
657                                                 if (++cnt < max_size) {
658                                                         putc(ch, op);
659                                                 }
660                                                 if ((ch == '\n') && (buffer_mode == _IOLBF)) {
661                                                         fflush(op);
662                                                 }
663                                         }
664                                 }
665                                 goto nextfmt;
666                         }
667
668                         fmt = fmt0;     /* this was an illegal format */
669                 }
670
671                 charout:
672                 if (++cnt < max_size) {
673                         putc(*fmt, op); /* normal char out */
674                 }
675                 if ((*fmt == '\n') && (buffer_mode == _IOLBF)) {
676                         fflush(op);
677                 }
678
679         nextfmt:
680                 ++fmt;
681         }
682
683         op->mode |= buffer_mode;
684         if (buffer_mode == _IOLBF) {
685                 op->bufwrite = op->bufpos;
686         }
687
688         if (ferror(op)) {
689                 cnt = -1;
690         }
691         return (cnt);
692 }
693
694 #endif
695