busybox/scripts/echo.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * echo implementation for busybox - used as a helper for testsuite/*
   4 * on systems lacking "echo -en"
   5 *
   6 * Copyright (c) 1991, 1993
   7 *      The Regents of the University of California.  All rights reserved.
   8 *
   9 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  10 *
  11 * Original copyright notice is retained at the end of this file.
  12 */
  13
  14/* BB_AUDIT SUSv3 compliant -- unless configured as fancy echo. */
  15/* http://www.opengroup.org/onlinepubs/007904975/utilities/echo.html */
  16
  17/* Mar 16, 2003      Manuel Novoa III   (mjn3@codepoet.org)
  18 *
  19 * Because of behavioral differences, implemented configurable SUSv3
  20 * or 'fancy' gnu-ish behaviors.  Also, reduced size and fixed bugs.
  21 * 1) In handling '\c' escape, the previous version only suppressed the
  22 *     trailing newline.  SUSv3 specifies _no_ output after '\c'.
  23 * 2) SUSv3 specifies that octal escapes are of the form \0{#{#{#}}}.
  24 *    The previous version did not allow 4-digit octals.
  25 */
  26
  27#include <stdio.h>
  28#include <string.h>
  29#include <limits.h>
  30#include <unistd.h>
  31
  32#define WANT_HEX_ESCAPES 1
  33
  34/* Usual "this only works for ascii compatible encodings" disclaimer. */
  35#undef _tolower
  36#define _tolower(X) ((X)|((char) 0x20))
  37
  38static char bb_process_escape_sequence(const char **ptr)
  39{
  40        static const char charmap[] = {
  41                'a',  'b',  'f',  'n',  'r',  't',  'v',  '\\', 0,
  42                '\a', '\b', '\f', '\n', '\r', '\t', '\v', '\\', '\\' };
  43
  44        const char *p;
  45        const char *q;
  46        unsigned int num_digits;
  47        unsigned int r;
  48        unsigned int n;
  49        unsigned int d;
  50        unsigned int base;
  51
  52        num_digits = n = 0;
  53        base = 8;
  54        q = *ptr;
  55
  56#ifdef WANT_HEX_ESCAPES
  57        if (*q == 'x') {
  58                ++q;
  59                base = 16;
  60                ++num_digits;
  61        }
  62#endif
  63
  64        do {
  65                d = (unsigned char)(*q) - '0';
  66#ifdef WANT_HEX_ESCAPES
  67                if (d >= 10) {
  68                        d = (unsigned char)(_tolower(*q)) - 'a' + 10;
  69                }
  70#endif
  71
  72                if (d >= base) {
  73#ifdef WANT_HEX_ESCAPES
  74                        if ((base == 16) && (!--num_digits)) {
  75/*                              return '\\'; */
  76                                --q;
  77                        }
  78#endif
  79                        break;
  80                }
  81
  82                r = n * base + d;
  83                if (r > UCHAR_MAX) {
  84                        break;
  85                }
  86
  87                n = r;
  88                ++q;
  89        } while (++num_digits < 3);
  90
  91        if (num_digits == 0) {  /* mnemonic escape sequence? */
  92                p = charmap;
  93                do {
  94                        if (*p == *q) {
  95                                q++;
  96                                break;
  97                        }
  98                } while (*++p);
  99                n = *(p + (sizeof(charmap)/2));
 100        }
 101
 102        *ptr = q;
 103
 104        return (char) n;
 105}
 106
 107
 108int main(int argc, char **argv)
 109{
 110        const char *arg;
 111        const char *p;
 112        char nflag = 1;
 113        char eflag = 0;
 114
 115        /* We must check that stdout is not closed. */
 116        if (dup2(1, 1) != 1)
 117                return -1;
 118
 119        while (1) {
 120                arg = *++argv;
 121                if (!arg)
 122                        goto newline_ret;
 123                if (*arg != '-')
 124                        break;
 125
 126                /* If it appears that we are handling options, then make sure
 127                 * that all of the options specified are actually valid.
 128                 * Otherwise, the string should just be echoed.
 129                 */
 130                p = arg + 1;
 131                if (!*p)        /* A single '-', so echo it. */
 132                        goto just_echo;
 133
 134                do {
 135                        if (!strrchr("neE", *p))
 136                                goto just_echo;
 137                } while (*++p);
 138
 139                /* All of the options in this arg are valid, so handle them. */
 140                p = arg + 1;
 141                do {
 142                        if (*p == 'n')
 143                                nflag = 0;
 144                        if (*p == 'e')
 145                                eflag = '\\';
 146                } while (*++p);
 147        }
 148 just_echo:
 149        while (1) {
 150                /* arg is already == *argv and isn't NULL */
 151                int c;
 152
 153                if (!eflag) {
 154                        /* optimization for very common case */
 155                        fputs(arg, stdout);
 156                } else while ((c = *arg++)) {
 157                        if (c == eflag) {       /* Check for escape seq. */
 158                                if (*arg == 'c') {
 159                                        /* '\c' means cancel newline and
 160                                         * ignore all subsequent chars. */
 161                                        goto ret;
 162                                }
 163                                {
 164                                        /* Since SUSv3 mandates a first digit of 0, 4-digit octals
 165                                        * of the form \0### are accepted. */
 166                                        if (*arg == '0') {
 167                                                /* NB: don't turn "...\0" into "...\" */
 168                                                if (arg[1] && ((unsigned char)(arg[1]) - '0') < 8) {
 169                                                        arg++;
 170                                                }
 171                                        }
 172                                        /* bb_process_escape_sequence handles NUL correctly
 173                                         * ("...\" case. */
 174                                        c = bb_process_escape_sequence(&arg);
 175                                }
 176                        }
 177                        putchar(c);
 178                }
 179
 180                arg = *++argv;
 181                if (!arg)
 182                        break;
 183                putchar(' ');
 184        }
 185
 186 newline_ret:
 187        if (nflag) {
 188                putchar('\n');
 189        }
 190 ret:
 191        return fflush(NULL);
 192}
 193
 194/*-
 195 * Copyright (c) 1991, 1993
 196 *      The Regents of the University of California.  All rights reserved.
 197 *
 198 * This code is derived from software contributed to Berkeley by
 199 * Kenneth Almquist.
 200 *
 201 * Redistribution and use in source and binary forms, with or without
 202 * modification, are permitted provided that the following conditions
 203 * are met:
 204 * 1. Redistributions of source code must retain the above copyright
 205 *    notice, this list of conditions and the following disclaimer.
 206 * 2. Redistributions in binary form must reproduce the above copyright
 207 *    notice, this list of conditions and the following disclaimer in the
 208 *    documentation and/or other materials provided with the distribution.
 209 *
 210 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
 211 *              ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
 212 *
 213 *      California, Berkeley and its contributors.
 214 * 4. Neither the name of the University nor the names of its contributors
 215 *    may be used to endorse or promote products derived from this software
 216 *    without specific prior written permission.
 217 *
 218 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND
 219 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 220 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 221 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 222 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 223 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 224 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 225 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 226 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 227 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 228 * SUCH DAMAGE.
 229 *
 230 *      @(#)echo.c      8.1 (Berkeley) 5/31/93
 231 */
 232