diff options
Diffstat (limited to 'busybox/libbb/printf.c')
-rw-r--r-- | busybox/libbb/printf.c | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/busybox/libbb/printf.c b/busybox/libbb/printf.c new file mode 100644 index 000000000..1156da911 --- /dev/null +++ b/busybox/libbb/printf.c | |||
@@ -0,0 +1,181 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * *printf implementations for busybox | ||
4 | * | ||
5 | * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
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 | */ | ||
22 | |||
23 | /* Mar 12, 2003 Manuel Novoa III | ||
24 | * | ||
25 | * While fwrite(), fputc(), fputs(), etc. all set the stream error flag | ||
26 | * on failure, the *printf functions are unique in that they can fail | ||
27 | * for reasons not related to the actual output itself. Among the possible | ||
28 | * reasons for failure which don't set the streams error indicator, | ||
29 | * SUSv3 lists EILSEQ, EINVAL, and ENOMEM. | ||
30 | * | ||
31 | * In some cases, it would be desirable to have a group of *printf() | ||
32 | * functions available that _always_ set the stream error indicator on | ||
33 | * failure. That would allow us to defer error checking until applet | ||
34 | * exit. Unfortunately, there is no standard way of setting a streams | ||
35 | * error indicator... even though we can clear it with clearerr(). | ||
36 | * | ||
37 | * Therefore, we have to resort to implementation dependent code. Feel | ||
38 | * free to send patches for stdio implementations where the following | ||
39 | * fails. | ||
40 | * | ||
41 | * NOTE: None of this is thread safe. As busybox is a non-threaded app, | ||
42 | * that isn't currently an issue. | ||
43 | */ | ||
44 | |||
45 | #include <stdio.h> | ||
46 | #include <stdarg.h> | ||
47 | #include "libbb.h" | ||
48 | |||
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(__GLIBC__) | ||
78 | |||
79 | # if defined(_STDIO_USES_IOSTREAM) | ||
80 | /* Apparently using the newer libio implementation, with associated defines: | ||
81 | * #define _IO_feof_unlocked(__fp) (((__fp)->_flags & _IO_EOF_SEEN) != 0) | ||
82 | * #define _IO_ferror_unlocked(__fp) (((__fp)->_flags & _IO_ERR_SEEN) != 0) | ||
83 | */ | ||
84 | #define SET_FERROR_UNLOCKED(S) ((S)->_flags |= _IO_ERR_SEEN) | ||
85 | |||
86 | # else | ||
87 | /* Assume the older version of glibc which used a bitfield entry | ||
88 | * as a stream error flag. The associated defines were: | ||
89 | * #define __clearerr(stream) ((stream)->__error = (stream)->__eof = 0) | ||
90 | * #define feof_unlocked(stream) ((stream)->__eof != 0) | ||
91 | * #define ferror_unlocked(stream) ((stream)->__error != 0) | ||
92 | */ | ||
93 | #define SET_FERROR_UNLOCKED(S) ((S)->__error = 1) | ||
94 | |||
95 | # endif | ||
96 | |||
97 | #elif defined(__NEWLIB_H__) | ||
98 | /* I honestly don't know if there are different versions of stdio in | ||
99 | * newlibs history. Anyway, here's what's current. | ||
100 | * #define __sfeof(p) (((p)->_flags & __SEOF) != 0) | ||
101 | * #define __sferror(p) (((p)->_flags & __SERR) != 0) | ||
102 | * #define __sclearerr(p) ((void)((p)->_flags &= ~(__SERR|__SEOF))) | ||
103 | */ | ||
104 | #define SET_FERROR_UNLOCKED(S) ((S)->_flags |= __SERR) | ||
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 | ||
133 | extern int bb_vfprintf(FILE * __restrict stream, | ||
134 | const char * __restrict format, | ||
135 | va_list arg) | ||
136 | { | ||
137 | int rv; | ||
138 | |||
139 | if ((rv = vfprintf(stream, format, arg)) < 0) { | ||
140 | SET_FERROR_UNLOCKED(stream); | ||
141 | } | ||
142 | |||
143 | return rv; | ||
144 | } | ||
145 | #endif | ||
146 | |||
147 | #ifdef L_bb_vprintf | ||
148 | extern int bb_vprintf(const char * __restrict format, va_list arg) | ||
149 | { | ||
150 | return bb_vfprintf(stdout, format, arg); | ||
151 | } | ||
152 | #endif | ||
153 | |||
154 | #ifdef L_bb_fprintf | ||
155 | extern int bb_fprintf(FILE * __restrict stream, | ||
156 | const char * __restrict format, ...) | ||
157 | { | ||
158 | va_list arg; | ||
159 | int rv; | ||
160 | |||
161 | va_start(arg, format); | ||
162 | rv = bb_vfprintf(stream, format, arg); | ||
163 | va_end(arg); | ||
164 | |||
165 | return rv; | ||
166 | } | ||
167 | #endif | ||
168 | |||
169 | #ifdef L_bb_printf | ||
170 | extern int bb_printf(const char * __restrict format, ...) | ||
171 | { | ||
172 | va_list arg; | ||
173 | int rv; | ||
174 | |||
175 | va_start(arg, format); | ||
176 | rv = bb_vfprintf(stdout, format, arg); | ||
177 | va_end(arg); | ||
178 | |||
179 | return rv; | ||
180 | } | ||
181 | #endif | ||