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