blob: 2e79555b5059a8525393412433f6ede04a69a239 [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 *
Rob Landleyfb3a6312006-03-23 15:30:26 +00007 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
Manuel Novoa III cad53642003-03-19 09:13:01 +00008 */
9
10/* Mar 12, 2003 Manuel Novoa III
11 *
12 * While fwrite(), fputc(), fputs(), etc. all set the stream error flag
13 * on failure, the *printf functions are unique in that they can fail
14 * for reasons not related to the actual output itself. Among the possible
15 * reasons for failure which don't set the streams error indicator,
16 * SUSv3 lists EILSEQ, EINVAL, and ENOMEM.
17 *
Eric Andersenaff114c2004-04-14 17:51:38 +000018 * In some cases, it would be desirable to have a group of *printf()
Manuel Novoa III cad53642003-03-19 09:13:01 +000019 * functions available that _always_ set the stream error indicator on
20 * failure. That would allow us to defer error checking until applet
21 * exit. Unfortunately, there is no standard way of setting a streams
22 * error indicator... even though we can clear it with clearerr().
Rob Landleyfb3a6312006-03-23 15:30:26 +000023 */
24
25/* Mar 22, 2006 Rich Felker III
Manuel Novoa III cad53642003-03-19 09:13:01 +000026 *
Rob Landleyfb3a6312006-03-23 15:30:26 +000027 * Actually there is a portable way to set the error indicator. See below.
28 * It is not thread-safe as written due to a race condition with file
29 * descriptors but since BB is not threaded that does not matter. It can be
30 * made thread-safe at the expense of slightly more code, if this is ever
31 * needed in the future.
Manuel Novoa III cad53642003-03-19 09:13:01 +000032 */
33
34#include <stdio.h>
35#include <stdarg.h>
Rob Landleyfb3a6312006-03-23 15:30:26 +000036#include <unistd.h>
37#include <errno.h>
Manuel Novoa III cad53642003-03-19 09:13:01 +000038#include "libbb.h"
39
Eric Andersen34365852003-04-16 23:02:35 +000040#ifdef L_bb_vfprintf
Rob Landleyca087712006-03-29 16:52:56 +000041int bb_vfprintf(FILE * __restrict stream,
Manuel Novoa III cad53642003-03-19 09:13:01 +000042 const char * __restrict format,
43 va_list arg)
44{
45 int rv;
46
47 if ((rv = vfprintf(stream, format, arg)) < 0) {
Rob Landleyfb3a6312006-03-23 15:30:26 +000048 /* 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;
Manuel Novoa III cad53642003-03-19 09:13:01 +000064 }
65
66 return rv;
67}
68#endif
69
Eric Andersen34365852003-04-16 23:02:35 +000070#ifdef L_bb_vprintf
Rob Landleydfba7412006-03-06 20:47:33 +000071int bb_vprintf(const char * __restrict format, va_list arg)
Manuel Novoa III cad53642003-03-19 09:13:01 +000072{
73 return bb_vfprintf(stdout, format, arg);
74}
75#endif
76
Eric Andersen34365852003-04-16 23:02:35 +000077#ifdef L_bb_fprintf
Rob Landleyca087712006-03-29 16:52:56 +000078int bb_fprintf(FILE * __restrict stream,
Manuel Novoa III cad53642003-03-19 09:13:01 +000079 const char * __restrict format, ...)
80{
81 va_list arg;
82 int rv;
83
84 va_start(arg, format);
85 rv = bb_vfprintf(stream, format, arg);
86 va_end(arg);
87
88 return rv;
89}
90#endif
91
Eric Andersen34365852003-04-16 23:02:35 +000092#ifdef L_bb_printf
Rob Landleydfba7412006-03-06 20:47:33 +000093int bb_printf(const char * __restrict format, ...)
Manuel Novoa III cad53642003-03-19 09:13:01 +000094{
95 va_list arg;
96 int rv;
97
98 va_start(arg, format);
99 rv = bb_vfprintf(stdout, format, arg);
100 va_end(arg);
101
102 return rv;
103}
104#endif