Changeset 3232 in MondoRescue for branches/3.2/mindi-busybox/coreutils/echo.c


Ignore:
Timestamp:
Jan 1, 2014, 12:47:38 AM (10 years ago)
Author:
Bruno Cornec
Message:
  • Update mindi-busybox to 1.21.1
File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/3.2/mindi-busybox/coreutils/echo.c

    r2725 r3232  
    2424 */
    2525
     26//usage:#define echo_trivial_usage
     27//usage:    IF_FEATURE_FANCY_ECHO("[-neE] ") "[ARG]..."
     28//usage:#define echo_full_usage "\n\n"
     29//usage:       "Print the specified ARGs to stdout"
     30//usage:    IF_FEATURE_FANCY_ECHO( "\n"
     31//usage:     "\n    -n  Suppress trailing newline"
     32//usage:     "\n    -e  Interpret backslash escapes (i.e., \\t=tab)"
     33//usage:     "\n    -E  Don't interpret backslash escapes (default)"
     34//usage:    )
     35//usage:
     36//usage:#define echo_example_usage
     37//usage:       "$ echo \"Erik is cool\"\n"
     38//usage:       "Erik is cool\n"
     39//usage:    IF_FEATURE_FANCY_ECHO("$ echo -e \"Erik\\nis\\ncool\"\n"
     40//usage:       "Erik\n"
     41//usage:       "is\n"
     42//usage:       "cool\n"
     43//usage:       "$ echo \"Erik\\nis\\ncool\"\n"
     44//usage:       "Erik\\nis\\ncool\n")
     45
    2646#include "libbb.h"
    2747
     
    2949
    3050/* NB: can be used by shell even if not enabled as applet */
     51
     52/*
     53 * NB2: we don't use stdio, we need better error handing.
     54 * Examples include writing into non-opened stdout and error on write.
     55 *
     56 * With stdio, output gets shoveled into stdout buffer, and even
     57 * fflush cannot clear it out. It seems that even if libc receives
     58 * EBADF on write attempts, it feels determined to output data no matter what.
     59 * If echo is called by shell, it will try writing again later, and possibly
     60 * will clobber future output. Not good.
     61 *
     62 * Solaris has fpurge which discards buffered input. glibc has __fpurge.
     63 * But this function is not standard.
     64 */
    3165
    3266int echo_main(int argc UNUSED_PARAM, char **argv)
    3367{
     68    char **pp;
    3469    const char *arg;
     70    char *out;
     71    char *buffer;
     72    unsigned buflen;
    3573#if !ENABLE_FEATURE_FANCY_ECHO
    3674    enum {
     
    3977    };
    4078
    41     /* We must check that stdout is not closed.
    42      * The reason for this is highly non-obvious.
    43      * echo_main is used from shell. Shell must correctly handle "echo foo"
    44      * if stdout is closed. With stdio, output gets shoveled into
    45      * stdout buffer, and even fflush cannot clear it out. It seems that
    46      * even if libc receives EBADF on write attempts, it feels determined
    47      * to output data no matter what. So it will try later,
    48      * and possibly will clobber future output. Not good. */
    49 // TODO: check fcntl() & O_ACCMODE == O_WRONLY or O_RDWR?
    50     if (fcntl(1, F_GETFL) == -1)
    51         return 1; /* match coreutils 6.10 (sans error msg to stderr) */
    52     //if (dup2(1, 1) != 1) - old way
    53     //  return 1;
    54 
    55     arg = *++argv;
    56     if (!arg)
    57         goto newline_ret;
     79    argv++;
    5880#else
    59     const char *p;
    6081    char nflag = 1;
    6182    char eflag = 0;
    6283
    63     /* We must check that stdout is not closed. */
    64     if (fcntl(1, F_GETFL) == -1)
    65         return 1;
    66 
    67     while (1) {
    68         arg = *++argv;
    69         if (!arg)
    70             goto newline_ret;
    71         if (*arg != '-')
    72             break;
     84    while ((arg = *++argv) != NULL) {
     85        char n, e;
     86
     87        if (arg[0] != '-')
     88            break; /* not an option arg, echo it */
    7389
    7490        /* If it appears that we are handling options, then make sure
     
    7692         * Otherwise, the string should just be echoed.
    7793         */
    78         p = arg + 1;
    79         if (!*p)    /* A single '-', so echo it. */
    80             goto just_echo;
    81 
     94        arg++;
     95        n = nflag;
     96        e = eflag;
    8297        do {
    83             if (!strrchr("neE", *p))
     98            if (*arg == 'n')
     99                n = 0;
     100            else if (*arg == 'e')
     101                e = '\\';
     102            else if (*arg != 'E') {
     103                /* "-ccc" arg with one of c's invalid, echo it */
     104                /* arg consisting from just "-" also handled here */
    84105                goto just_echo;
    85         } while (*++p);
    86 
    87         /* All of the options in this arg are valid, so handle them. */
    88         p = arg + 1;
    89         do {
    90             if (*p == 'n')
    91                 nflag = 0;
    92             if (*p == 'e')
    93                 eflag = '\\';
    94         } while (*++p);
     106            }
     107        } while (*++arg);
     108        nflag = n;
     109        eflag = e;
    95110    }
    96111 just_echo:
    97112#endif
    98     while (1) {
    99         /* arg is already == *argv and isn't NULL */
     113
     114    buflen = 0;
     115    pp = argv;
     116    while ((arg = *pp) != NULL) {
     117        buflen += strlen(arg) + 1;
     118        pp++;
     119    }
     120    out = buffer = xmalloc(buflen + 1); /* +1 is needed for "no args" case */
     121
     122    while ((arg = *argv) != NULL) {
    100123        int c;
    101124
    102125        if (!eflag) {
    103126            /* optimization for very common case */
    104             fputs(arg, stdout);
    105         } else while ((c = *arg++)) {
    106             if (c == eflag) {   /* Check for escape seq. */
     127            out = stpcpy(out, arg);
     128        } else
     129        while ((c = *arg++) != '\0') {
     130            if (c == eflag) {
     131                /* This is an "\x" sequence */
     132
    107133                if (*arg == 'c') {
    108                     /* '\c' means cancel newline and
     134                    /* "\c" means cancel newline and
    109135                     * ignore all subsequent chars. */
    110                     goto ret;
    111                 }
    112 #if !ENABLE_FEATURE_FANCY_ECHO
    113                 /* SUSv3 specifies that octal escapes must begin with '0'. */
    114                 if ( ((int)(unsigned char)(*arg) - '0') >= 8) /* '8' or bigger */
    115 #endif
     136                    goto do_write;
     137                }
     138                /* Since SUSv3 mandates a first digit of 0, 4-digit octals
     139                * of the form \0### are accepted. */
     140                if (*arg == '0') {
     141                    if ((unsigned char)(arg[1] - '0') < 8) {
     142                        /* 2nd char is 0..7: skip leading '0' */
     143                        arg++;
     144                    }
     145                }
     146                /* bb_process_escape_sequence handles NUL correctly
     147                 * ("...\" case). */
    116148                {
    117                     /* Since SUSv3 mandates a first digit of 0, 4-digit octals
    118                     * of the form \0### are accepted. */
    119                     if (*arg == '0') {
    120                         /* NB: don't turn "...\0" into "...\" */
    121                         if (arg[1] && ((unsigned char)(arg[1]) - '0') < 8) {
    122                             arg++;
    123                         }
    124                     }
    125                     /* bb_process_escape_sequence handles NUL correctly
    126                      * ("...\" case). */
    127                     c = bb_process_escape_sequence(&arg);
     149                    /* optimization: don't force arg to be on-stack,
     150                     * use another variable for that. ~30 bytes win */
     151                    const char *z = arg;
     152                    c = bb_process_escape_sequence(&z);
     153                    arg = z;
    128154                }
    129155            }
    130             bb_putchar(c);
     156            *out++ = c;
    131157        }
    132158
    133         arg = *++argv;
    134         if (!arg)
     159        if (!*++argv)
    135160            break;
    136         bb_putchar(' ');
    137     }
    138 
    139  newline_ret:
     161        *out++ = ' ';
     162    }
     163
    140164    if (nflag) {
    141         bb_putchar('\n');
    142     }
    143  ret:
    144     return fflush_all();
     165        *out++ = '\n';
     166    }
     167
     168 do_write:
     169    /* Careful to error out on partial writes too (think ENOSPC!) */
     170    errno = 0;
     171    /*r =*/ full_write(STDOUT_FILENO, buffer, out - buffer);
     172    free(buffer);
     173    if (/*WRONG:r < 0*/ errno) {
     174        bb_perror_msg(bb_msg_write_error);
     175        return 1;
     176    }
     177    return 0;
    145178}
    146179
    147 /*-
     180/*
    148181 * Copyright (c) 1991, 1993
    149182 *  The Regents of the University of California.  All rights reserved.
     
    231264
    232265        do {
    233             if (!strrchr("neE", *p))
     266            if (!strchr("neE", *p))
    234267                goto just_echo;
    235268        } while (*++p);
     
    257290            p += strlen(arg);
    258291        } else while ((c = *arg++)) {
    259             if (c == eflag) {   /* Check for escape seq. */
     292            if (c == eflag) {
     293                /* This is an "\x" sequence */
     294
    260295                if (*arg == 'c') {
    261                     /* '\c' means cancel newline and
     296                    /* "\c" means cancel newline and
    262297                     * ignore all subsequent chars. */
    263298                    cur_io->iov_len = p - (char*)cur_io->iov_base;
     
    265300                    goto ret;
    266301                }
    267 #if !ENABLE_FEATURE_FANCY_ECHO
    268                 /* SUSv3 specifies that octal escapes must begin with '0'. */
    269                 if ( (((unsigned char)*arg) - '1') >= 7)
    270 #endif
    271                 {
    272                     /* Since SUSv3 mandates a first digit of 0, 4-digit octals
    273                     * of the form \0### are accepted. */
    274                     if (*arg == '0' && ((unsigned char)(arg[1]) - '0') < 8) {
    275                         arg++;
    276                     }
    277                     /* bb_process_escape_sequence can handle nul correctly */
    278                     c = bb_process_escape_sequence( (void*) &arg);
    279                 }
     302                /* Since SUSv3 mandates a first digit of 0, 4-digit octals
     303                * of the form \0### are accepted. */
     304                if (*arg == '0' && (unsigned char)(arg[1] - '0') < 8) {
     305                    arg++;
     306                }
     307                /* bb_process_escape_sequence can handle nul correctly */
     308                c = bb_process_escape_sequence( (void*) &arg);
    280309            }
    281310            *p++ = c;
Note: See TracChangeset for help on using the changeset viewer.