- register char *p = escstart + 1;
- int esc_value = 0; /* Value of \nnn escape. */
- int esc_length; /* Length of \nnn escape. */
-
- /* \0ooo and \xhhh escapes have maximum length of 3 chars. */
- if (*p == 'x') {
- for (esc_length = 0, ++p;
- esc_length < 3 && ISXDIGIT(*p); ++esc_length, ++p)
- esc_value = esc_value * 16 + hextobin(*p);
-/* if (esc_length == 0)
- fprintf(stderr, "missing hex in esc");
-*/
- putchar(esc_value);
- } else if (*p == '0') {
- for (esc_length = 0, ++p;
- esc_length < 3 && isodigit(*p); ++esc_length, ++p)
- esc_value = esc_value * 8 + octtobin(*p);
- putchar(esc_value);
- } else if (strchr("\"\\abcfnrtv", *p))
- print_esc_char(*p++);
-/* else
- fprintf(stderr, "\\%c: invalid esc", *p);
-*/
- return p - escstart - 1;
-}
-
-/* Output a single-character \ escape. */
-
-static void print_esc_char(int c)
-{
- switch (c) {
- case 'a': /* Alert. */
- putchar(7);
- break;
- case 'b': /* Backspace. */
- putchar(8);
- break;
- case 'c': /* Cancel the rest of the output. */
- exit(0);
- break;
- case 'f': /* Form feed. */
- putchar(12);
- break;
- case 'n': /* New line. */
- putchar(10);
- break;
- case 'r': /* Carriage return. */
- putchar(13);
- break;
- case 't': /* Horizontal tab. */
- putchar(9);
- break;
- case 'v': /* Vertical tab. */
- putchar(11);
- break;
- default:
- putchar(c);
- break;
- }
-}
-
-/* Print string STR, evaluating \ escapes. */
-
-static void print_esc_string(char *str)
-{
- for (; *str; str++)
- if (*str == '\\')
- str += print_esc(str);
- else
- putchar(*str);
-}
-
-static void
-print_direc(char *start, size_t length, int field_width, int precision,
- char *argument)
-{
- char *p; /* Null-terminated copy of % directive. */
-
- p = xmalloc((unsigned) (length + 1));
- strncpy(p, start, length);
- p[length] = 0;
-
- switch (p[length - 1]) {
- case 'd':
- case 'i':
- if (field_width < 0) {
- if (precision < 0)
- printf(p, xstrtol(argument));
- else
- printf(p, precision, xstrtol(argument));
- } else {
- if (precision < 0)
- printf(p, field_width, xstrtol(argument));
- else
- printf(p, field_width, precision, xstrtol(argument));
- }
- break;
-
- case 'o':
- case 'u':
- case 'x':
- case 'X':
- if (field_width < 0) {
- if (precision < 0)
- printf(p, xstrtoul(argument));
- else
- printf(p, precision, xstrtoul(argument));
- } else {
- if (precision < 0)
- printf(p, field_width, xstrtoul(argument));
- else
- printf(p, field_width, precision, xstrtoul(argument));
- }
- break;
-
- case 'f':
- case 'e':
- case 'E':
- case 'g':
- case 'G':
- if (field_width < 0) {
- if (precision < 0)
- printf(p, xstrtod(argument));
- else
- printf(p, precision, xstrtod(argument));
- } else {
- if (precision < 0)
- printf(p, field_width, xstrtod(argument));
- else
- printf(p, field_width, precision, xstrtod(argument));
- }
- break;
-
- case 'c':
- printf(p, *argument);
- break;
-
- case 's':
- if (field_width < 0) {
- if (precision < 0)
- printf(p, argument);
- else
- printf(p, precision, argument);
- } else {
- if (precision < 0)
- printf(p, field_width, argument);
- else
- printf(p, field_width, precision, argument);
+ int conv_err;
+ char *format;
+ char **argv2;
+
+ /* We must check that stdout is not closed.
+ * The reason for this is highly non-obvious.
+ * printf_main is used from shell.
+ * Shell must correctly handle 'printf "%s" foo'
+ * if stdout is closed. With stdio, output gets shoveled into
+ * stdout buffer, and even fflush cannot clear it out. It seems that
+ * even if libc receives EBADF on write attempts, it feels determined
+ * to output data no matter what. So it will try later,
+ * and possibly will clobber future output. Not good. */
+// TODO: check fcntl() & O_ACCMODE == O_WRONLY or O_RDWR?
+ if (fcntl(1, F_GETFL) == -1)
+ return 1; /* match coreutils 6.10 (sans error msg to stderr) */
+ //if (dup2(1, 1) != 1) - old way
+ // return 1;
+
+ /* bash builtin errors out on "printf '-%s-\n' foo",
+ * coreutils-6.9 works. Both work with "printf -- '-%s-\n' foo".
+ * We will mimic coreutils. */
+ if (argv[1] && argv[1][0] == '-' && argv[1][1] == '-' && !argv[1][2])
+ argv++;
+ if (!argv[1]) {
+ if (ENABLE_ASH_BUILTIN_PRINTF
+ && applet_name[0] != 'p'
+ ) {
+ bb_error_msg("usage: printf FORMAT [ARGUMENT...]");
+ return 2; /* bash compat */