rename functions to more understandable names
[oweals/busybox.git] / libbb / printf.c
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  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8  */
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  *
18  * In some cases, it would be desirable to have a group of *printf()
19  * 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().
23  */
24
25 /* Mar 22, 2006     Rich Felker III
26  *
27  * 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.
32  */
33
34 #include <stdio.h>
35 #include <stdarg.h>
36 #include <unistd.h>
37 #include <errno.h>
38 #include "libbb.h"
39
40 int bb_vfprintf(FILE * __restrict stream,
41                                            const char * __restrict format,
42                                            va_list arg)
43 {
44         int rv;
45
46         if ((rv = vfprintf(stream, format, arg)) < 0) {
47                 /* The following sequence portably sets the error flag for
48                  * stream on any remotely POSIX-compliant implementation. */
49
50                 int errno_save = errno;
51                 int fd = fileno(stream);
52                 int tmp = dup(fd);
53
54                 fflush(stream);
55                 close(fd);
56                 /* Force an attempted write to nonexistant fd => EBADF */
57                 fputc(0, stream);
58                 fflush(stream);
59                 /* Restore the stream's original fd */
60                 dup2(tmp, fd);
61                 close(tmp);
62                 errno = errno_save;
63         }
64
65         return rv;
66 }
67
68 int bb_vprintf(const char * __restrict format, va_list arg)
69 {
70         return bb_vfprintf(stdout, format, arg);
71 }
72
73 int bb_fprintf(FILE * __restrict stream,
74                                           const char * __restrict format, ...)
75 {
76         va_list arg;
77         int rv;
78
79         va_start(arg, format);
80         rv = bb_vfprintf(stream, format, arg);
81         va_end(arg);
82
83         return rv;
84 }
85
86 int bb_printf(const char * __restrict format, ...)
87 {
88         va_list arg;
89         int rv;
90
91         va_start(arg, format);
92         rv = bb_vfprintf(stdout, format, arg);
93         va_end(arg);
94
95         return rv;
96 }