Bump to version 1.22.1
[platform/upstream/busybox.git] / scripts / echo.c
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
37 static 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
107 int 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  */