blob: 3e69331c5b0a559f47db3895c60ef6c0982ef8c1 [file] [log] [blame]
Manuel Novoa III cad53642003-03-19 09:13:01 +00001/* 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 desireable 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 threadsafe. As busybox is a nonthreaded 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 */
Manuel Novoa III ebce2da2004-01-30 21:44:20 +000058# 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
Manuel Novoa III cad53642003-03-19 09:13:01 +000063
Manuel Novoa III ebce2da2004-01-30 21:44:20 +000064# elif defined(__MODE_ERR)
Manuel Novoa III cad53642003-03-19 09:13:01 +000065/* 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
Manuel Novoa III ebce2da2004-01-30 21:44:20 +000073# else
Manuel Novoa III cad53642003-03-19 09:13:01 +000074#error unknown uClibc stdio implemenation!
Manuel Novoa III ebce2da2004-01-30 21:44:20 +000075# endif
Manuel Novoa III cad53642003-03-19 09:13:01 +000076
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, contary 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 libaries 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
Eric Andersen34365852003-04-16 23:02:35 +0000132#ifdef L_bb_vfprintf
Manuel Novoa III cad53642003-03-19 09:13:01 +0000133extern 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
Eric Andersen34365852003-04-16 23:02:35 +0000147#ifdef L_bb_vprintf
Manuel Novoa III cad53642003-03-19 09:13:01 +0000148extern int bb_vprintf(const char * __restrict format, va_list arg)
149{
150 return bb_vfprintf(stdout, format, arg);
151}
152#endif
153
Eric Andersen34365852003-04-16 23:02:35 +0000154#ifdef L_bb_fprintf
Manuel Novoa III cad53642003-03-19 09:13:01 +0000155extern 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
Eric Andersen34365852003-04-16 23:02:35 +0000169#ifdef L_bb_printf
Manuel Novoa III cad53642003-03-19 09:13:01 +0000170extern 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