printf.c 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  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. /* Mar 12, 2003 Manuel Novoa III
  10. *
  11. * While fwrite(), fputc(), fputs(), etc. all set the stream error flag
  12. * on failure, the *printf functions are unique in that they can fail
  13. * for reasons not related to the actual output itself. Among the possible
  14. * reasons for failure which don't set the streams error indicator,
  15. * SUSv3 lists EILSEQ, EINVAL, and ENOMEM.
  16. *
  17. * In some cases, it would be desirable to have a group of *printf()
  18. * functions available that _always_ set the stream error indicator on
  19. * failure. That would allow us to defer error checking until applet
  20. * exit. Unfortunately, there is no standard way of setting a streams
  21. * error indicator... even though we can clear it with clearerr().
  22. */
  23. /* Mar 22, 2006 Rich Felker III
  24. *
  25. * Actually there is a portable way to set the error indicator. See below.
  26. * It is not thread-safe as written due to a race condition with file
  27. * descriptors but since BB is not threaded that does not matter. It can be
  28. * made thread-safe at the expense of slightly more code, if this is ever
  29. * needed in the future.
  30. */
  31. #include <stdio.h>
  32. #include <stdarg.h>
  33. #include <unistd.h>
  34. #include <errno.h>
  35. #include "libbb.h"
  36. #ifdef L_bb_vfprintf
  37. int bb_vfprintf(FILE * __restrict stream,
  38. const char * __restrict format,
  39. va_list arg)
  40. {
  41. int rv;
  42. if ((rv = vfprintf(stream, format, arg)) < 0) {
  43. /* The following sequence portably sets the error flag for
  44. * stream on any remotely POSIX-compliant implementation. */
  45. int errno_save = errno;
  46. int fd = fileno(stream);
  47. int tmp = dup(fd);
  48. fflush(stream);
  49. close(fd);
  50. /* Force an attempted write to nonexistant fd => EBADF */
  51. fputc(0, stream);
  52. fflush(stream);
  53. /* Restore the stream's original fd */
  54. dup2(tmp, fd);
  55. close(tmp);
  56. errno = errno_save;
  57. }
  58. return rv;
  59. }
  60. #endif
  61. #ifdef L_bb_vprintf
  62. int bb_vprintf(const char * __restrict format, va_list arg)
  63. {
  64. return bb_vfprintf(stdout, format, arg);
  65. }
  66. #endif
  67. #ifdef L_bb_fprintf
  68. int bb_fprintf(FILE * __restrict stream,
  69. const char * __restrict format, ...)
  70. {
  71. va_list arg;
  72. int rv;
  73. va_start(arg, format);
  74. rv = bb_vfprintf(stream, format, arg);
  75. va_end(arg);
  76. return rv;
  77. }
  78. #endif
  79. #ifdef L_bb_printf
  80. int bb_printf(const char * __restrict format, ...)
  81. {
  82. va_list arg;
  83. int rv;
  84. va_start(arg, format);
  85. rv = bb_vfprintf(stdout, format, arg);
  86. va_end(arg);
  87. return rv;
  88. }
  89. #endif