aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlandley <landley@69ca8d6d-28ef-0310-b511-8ec308f3f277>2006-03-23 15:30:26 +0000
committerlandley <landley@69ca8d6d-28ef-0310-b511-8ec308f3f277>2006-03-23 15:30:26 +0000
commit44889afec9f741df75db599aed1e1cb0964fd78e (patch)
tree2e1bcd47d18f5b2aaba0e34984a9fd2acc18823f
parent0b4d9e8058b70631bac37fbd91f3f05eda2ef6bd (diff)
downloadbusybox-w32-44889afec9f741df75db599aed1e1cb0964fd78e.tar.gz
busybox-w32-44889afec9f741df75db599aed1e1cb0964fd78e.tar.bz2
busybox-w32-44889afec9f741df75db599aed1e1cb0964fd78e.zip
Very nice patch from Rich Felker to portably set the stream error indicator and
thus remove a lot of nasty old code that didn't. git-svn-id: svn://busybox.net/trunk/busybox@14627 69ca8d6d-28ef-0310-b511-8ec308f3f277
-rw-r--r--libbb/printf.c131
1 files changed, 27 insertions, 104 deletions
diff --git a/libbb/printf.c b/libbb/printf.c
index e61723242..7eb60a91e 100644
--- a/libbb/printf.c
+++ b/libbb/printf.c
@@ -4,20 +4,7 @@
4 * 4 *
5 * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org> 5 * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
6 * 6 *
7 * This program is free software; you can redistribute it and/or modify 7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */ 8 */
22 9
23/* Mar 12, 2003 Manuel Novoa III 10/* Mar 12, 2003 Manuel Novoa III
@@ -33,102 +20,23 @@
33 * failure. That would allow us to defer error checking until applet 20 * failure. That would allow us to defer error checking until applet
34 * exit. Unfortunately, there is no standard way of setting a streams 21 * exit. Unfortunately, there is no standard way of setting a streams
35 * error indicator... even though we can clear it with clearerr(). 22 * error indicator... even though we can clear it with clearerr().
23 */
24
25/* Mar 22, 2006 Rich Felker III
36 * 26 *
37 * Therefore, we have to resort to implementation dependent code. Feel 27 * Actually there is a portable way to set the error indicator. See below.
38 * free to send patches for stdio implementations where the following 28 * It is not thread-safe as written due to a race condition with file
39 * fails. 29 * descriptors but since BB is not threaded that does not matter. It can be
40 * 30 * made thread-safe at the expense of slightly more code, if this is ever
41 * NOTE: None of this is thread safe. As busybox is a non-threaded app, 31 * needed in the future.
42 * that isn't currently an issue.
43 */ 32 */
44 33
45#include <stdio.h> 34#include <stdio.h>
46#include <stdarg.h> 35#include <stdarg.h>
36#include <unistd.h>
37#include <errno.h>
47#include "libbb.h" 38#include "libbb.h"
48 39
49#if defined(__UCLIBC__)
50
51# if defined(__FLAG_ERROR)
52/* Using my newer stdio implementation. Unlocked macros are:
53 * #define __CLEARERR(stream) \
54 ((stream)->modeflags &= ~(__FLAG_EOF|__FLAG_ERROR), (void)0)
55 * #define __FEOF(stream) ((stream)->modeflags & __FLAG_EOF)
56 * #define __FERROR(stream) ((stream)->modeflags & __FLAG_ERROR)
57 */
58# if defined(__MASK_READING)
59# define SET_FERROR_UNLOCKED(S) ((S)->__modeflags |= __FLAG_ERROR)
60# else
61# define SET_FERROR_UNLOCKED(S) ((S)->modeflags |= __FLAG_ERROR)
62# endif
63
64# elif defined(__MODE_ERR)
65/* Using either the original stdio implementation (from dev86) or
66 * my original stdio rewrite. Macros were:
67 * #define ferror(fp) (((fp)->mode&__MODE_ERR) != 0)
68 * #define feof(fp) (((fp)->mode&__MODE_EOF) != 0)
69 * #define clearerr(fp) ((fp)->mode &= ~(__MODE_EOF|__MODE_ERR),0)
70 */
71#define SET_FERROR_UNLOCKED(S) ((S)->mode |= __MODE_ERR)
72
73# else
74# error unknown uClibc stdio implemenation!
75# endif
76
77#elif defined(__NEWLIB_H__)
78/* I honestly don't know if there are different versions of stdio in
79 * newlibs history. Anyway, here's what's current.
80 * #define __sfeof(p) (((p)->_flags & __SEOF) != 0)
81 * #define __sferror(p) (((p)->_flags & __SERR) != 0)
82 * #define __sclearerr(p) ((void)((p)->_flags &= ~(__SERR|__SEOF)))
83 */
84# define SET_FERROR_UNLOCKED(S) ((S)->_flags |= __SERR)
85
86#elif defined(__GLIBC__)
87
88# if defined(_STDIO_USES_IOSTREAM)
89/* Apparently using the newer libio implementation, with associated defines:
90 * #define _IO_feof_unlocked(__fp) (((__fp)->_flags & _IO_EOF_SEEN) != 0)
91 * #define _IO_ferror_unlocked(__fp) (((__fp)->_flags & _IO_ERR_SEEN) != 0)
92 */
93# define SET_FERROR_UNLOCKED(S) ((S)->_flags |= _IO_ERR_SEEN)
94
95# else
96/* Assume the older version of glibc which used a bitfield entry
97 * as a stream error flag. The associated defines were:
98 * #define __clearerr(stream) ((stream)->__error = (stream)->__eof = 0)
99 * #define feof_unlocked(stream) ((stream)->__eof != 0)
100 * #define ferror_unlocked(stream) ((stream)->__error != 0)
101 */
102# define SET_FERROR_UNLOCKED(S) ((S)->__error = 1)
103
104# endif
105
106#elif defined(__dietlibc__)
107/*
108 * WARNING!!! dietlibc is quite buggy. WARNING!!!
109 *
110 * Some example bugs as of March 12, 2003...
111 * 1) fputc() doesn't set the error indicator on failure.
112 * 2) freopen() doesn't maintain the same stream object, contrary to
113 * standards. This makes it useless in its primary role of
114 * reassociating stdin/stdout/stderr.
115 * 3) printf() often fails to correctly format output when conversions
116 * involve padding. It is also practically useless for floating
117 * point output.
118 *
119 * But, if you're determined to use it anyway, (as of the current version)
120 * you can extract the information you need from dietstdio.h. See the
121 * other library implementations for examples.
122 */
123# error dietlibc is currently not supported. Please see the commented source.
124
125#else /* some other lib */
126/* Please see the comments for the above supported libraries for examples
127 * of what is required to support your stdio implementation.
128 */
129# error Your stdio library is currently not supported. Please see the commented source.
130#endif
131
132#ifdef L_bb_vfprintf 40#ifdef L_bb_vfprintf
133extern int bb_vfprintf(FILE * __restrict stream, 41extern int bb_vfprintf(FILE * __restrict stream,
134 const char * __restrict format, 42 const char * __restrict format,
@@ -137,7 +45,22 @@ extern int bb_vfprintf(FILE * __restrict stream,
137 int rv; 45 int rv;
138 46
139 if ((rv = vfprintf(stream, format, arg)) < 0) { 47 if ((rv = vfprintf(stream, format, arg)) < 0) {
140 SET_FERROR_UNLOCKED(stream); 48 /* The following sequence portably sets the error flag for
49 * stream on any remotely POSIX-compliant implementation. */
50
51 int errno_save = errno;
52 int fd = fileno(stream);
53 int tmp = dup(fd);
54
55 fflush(stream);
56 close(fd);
57 /* Force an attempted write to nonexistant fd => EBADF */
58 fputc(0, stream);
59 fflush(stream);
60 /* Restore the stream's original fd */
61 dup2(tmp, fd);
62 close(tmp);
63 errno = errno_save;
141 } 64 }
142 65
143 return rv; 66 return rv;