Tizen 2.0 Release
[external/tizen-coreutils.git] / src / echo.c
1 /* echo.c, derived from code echo.c in Bash.
2    Copyright (C) 87,89, 1991-1997, 1999-2005 Free Software Foundation, Inc.
3
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2, or (at your option)
7    any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software Foundation,
16    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
17
18 #include <config.h>
19 #include <stdio.h>
20 #include <sys/types.h>
21 #include "system.h"
22 #include "long-options.h"
23
24 /* The official name of this program (e.g., no `g' prefix).  */
25 #define PROGRAM_NAME "echo"
26
27 #define AUTHORS "FIXME unknown"
28
29 /* echo [-neE] [arg ...]
30 Output the ARGs.  If -n is specified, the trailing newline is
31 suppressed.  If the -e option is given, interpretation of the
32 following backslash-escaped characters is turned on:
33         \a      alert (bell)
34         \b      backspace
35         \c      suppress trailing newline
36         \f      form feed
37         \n      new line
38         \r      carriage return
39         \t      horizontal tab
40         \v      vertical tab
41         \\      backslash
42         \0NNN   the character whose ASCII code is NNN (octal).
43
44 You can explicitly turn off the interpretation of the above characters
45 on System V systems with the -E option.
46 */
47
48 /* If true, interpret backslash escapes by default.  */
49 #ifndef DEFAULT_ECHO_TO_XPG
50 enum { DEFAULT_ECHO_TO_XPG = false };
51 #endif
52
53 /* The name this program was run with. */
54 char *program_name;
55
56 void
57 usage (int status)
58 {
59   if (status != EXIT_SUCCESS)
60     fprintf (stderr, _("Try `%s --help' for more information.\n"),
61              program_name);
62   else
63     {
64       printf (_("Usage: %s [OPTION]... [STRING]...\n"), program_name);
65       fputs (_("\
66 Echo the STRING(s) to standard output.\n\
67 \n\
68   -n             do not output the trailing newline\n\
69 "), stdout);
70       fputs (_(DEFAULT_ECHO_TO_XPG
71                ? "\
72   -e             enable interpretation of backslash escapes (default)\n\
73   -E             disable interpretation of backslash escapes\n"
74                : "\
75   -e             enable interpretation of backslash escapes\n\
76   -E             disable interpretation of backslash escapes (default)\n"),
77              stdout);
78       fputs (HELP_OPTION_DESCRIPTION, stdout);
79       fputs (VERSION_OPTION_DESCRIPTION, stdout);
80       fputs (_("\
81 \n\
82 If -e is in effect, the following sequences are recognized:\n\
83 \n\
84   \\0NNN   the character whose ASCII code is NNN (octal)\n\
85   \\\\     backslash\n\
86   \\a     alert (BEL)\n\
87   \\b     backspace\n\
88 "), stdout);
89       fputs (_("\
90   \\c     suppress trailing newline\n\
91   \\f     form feed\n\
92   \\n     new line\n\
93   \\r     carriage return\n\
94   \\t     horizontal tab\n\
95   \\v     vertical tab\n\
96 "), stdout);
97       printf (USAGE_BUILTIN_WARNING, PROGRAM_NAME);
98       printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
99     }
100   exit (status);
101 }
102
103 /* Convert C from hexadecimal character to integer.  */
104 static int
105 hextobin (unsigned char c)
106 {
107   switch (c)
108     {
109     default: return c - '0';
110     case 'a': case 'A': return 10;
111     case 'b': case 'B': return 11;
112     case 'c': case 'C': return 12;
113     case 'd': case 'D': return 13;
114     case 'e': case 'E': return 14;
115     case 'f': case 'F': return 15;
116     }
117 }
118
119 /* Print the words in LIST to standard output.  If the first word is
120    `-n', then don't print a trailing newline.  We also support the
121    echo syntax from Version 9 unix systems. */
122
123 int
124 main (int argc, char **argv)
125 {
126   bool display_return = true;
127   bool allow_options =
128     (! getenv ("POSIXLY_CORRECT")
129      || (! DEFAULT_ECHO_TO_XPG && 1 < argc && STREQ (argv[1], "-n")));
130
131   /* System V machines already have a /bin/sh with a v9 behavior.
132      Use the identical behavior for these machines so that the
133      existing system shell scripts won't barf.  */
134   bool do_v9 = DEFAULT_ECHO_TO_XPG;
135
136   initialize_main (&argc, &argv);
137   program_name = argv[0];
138   setlocale (LC_ALL, "");
139   bindtextdomain (PACKAGE, LOCALEDIR);
140   textdomain (PACKAGE);
141
142   atexit (close_stdout);
143
144   if (allow_options)
145     parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
146                         usage, AUTHORS, (char const *) NULL);
147
148   --argc;
149   ++argv;
150
151   if (allow_options)
152     while (argc > 0 && *argv[0] == '-')
153       {
154         char const *temp = argv[0] + 1;
155         size_t i;
156
157         /* If it appears that we are handling options, then make sure that
158            all of the options specified are actually valid.  Otherwise, the
159            string should just be echoed.  */
160
161         for (i = 0; temp[i]; i++)
162           switch (temp[i])
163             {
164             case 'e': case 'E': case 'n':
165               break;
166             default:
167               goto just_echo;
168             }
169
170         if (i == 0)
171           goto just_echo;
172
173         /* All of the options in TEMP are valid options to ECHO.
174            Handle them. */
175         while (*temp)
176           switch (*temp++)
177             {
178             case 'e':
179               do_v9 = true;
180               break;
181
182             case 'E':
183               do_v9 = false;
184               break;
185
186             case 'n':
187               display_return = false;
188               break;
189             }
190
191         argc--;
192         argv++;
193       }
194
195 just_echo:
196
197   if (do_v9)
198     {
199       while (argc > 0)
200         {
201           char const *s = argv[0];
202           unsigned char c;
203
204           while ((c = *s++))
205             {
206               if (c == '\\' && *s)
207                 {
208                   switch (c = *s++)
209                     {
210                     case 'a': c = '\a'; break;
211                     case 'b': c = '\b'; break;
212                     case 'c': exit (EXIT_SUCCESS);
213                     case 'f': c = '\f'; break;
214                     case 'n': c = '\n'; break;
215                     case 'r': c = '\r'; break;
216                     case 't': c = '\t'; break;
217                     case 'v': c = '\v'; break;
218                     case 'x':
219                       {
220                         unsigned char ch = *s;
221                         if (! isxdigit (ch))
222                           goto not_an_escape;
223                         s++;
224                         c = hextobin (ch);
225                         ch = *s;
226                         if (isxdigit (ch))
227                           {
228                             s++;
229                             c = c * 16 + hextobin (ch);
230                           }
231                       }
232                       break;
233                     case '0':
234                       c = 0;
235                       if (! ('0' <= *s && *s <= '7'))
236                         break;
237                       c = *s++;
238                       /* Fall through.  */
239                     case '1': case '2': case '3':
240                     case '4': case '5': case '6': case '7':
241                       c -= '0';
242                       if ('0' <= *s && *s <= '7')
243                         c = c * 8 + (*s++ - '0');
244                       if ('0' <= *s && *s <= '7')
245                         c = c * 8 + (*s++ - '0');
246                       break;
247                     case '\\': break;
248
249                     not_an_escape:
250                     default:  putchar ('\\'); break;
251                     }
252                 }
253               putchar (c);
254             }
255           argc--;
256           argv++;
257           if (argc > 0)
258             putchar (' ');
259         }
260     }
261   else
262     {
263       while (argc > 0)
264         {
265           fputs (argv[0], stdout);
266           argc--;
267           argv++;
268           if (argc > 0)
269             putchar (' ');
270         }
271     }
272
273   if (display_return)
274     putchar ('\n');
275   exit (EXIT_SUCCESS);
276 }