dfaf0aa31896eeb653c998c51099e114eac6cfd9
[platform/upstream/coreutils.git] / src / echo.c
1 /* echo.c, derived from code echo.c in Bash.
2    Copyright (C) 87,89, 1991-1997, 1999-2002 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 WRITTEN_BY _("Written by 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         \num    the character whose ASCII code is NUM (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 defined, interpret backslash escapes if -e is given.  */
49 #define V9_ECHO
50
51 /* If defined, interpret backslash escapes unless -E is given.
52    V9_ECHO must also be defined.  */
53 /* #define V9_DEFAULT */
54
55 #if defined (V9_ECHO)
56 # if defined (V9_DEFAULT)
57 #  define VALID_ECHO_OPTIONS "neE"
58 # else
59 #  define VALID_ECHO_OPTIONS "ne"
60 # endif /* !V9_DEFAULT */
61 #else /* !V9_ECHO */
62 # define VALID_ECHO_OPTIONS "n"
63 #endif /* !V9_ECHO */
64
65 /* The name this program was run with. */
66 char *program_name;
67
68 void
69 usage (int status)
70 {
71   if (status != 0)
72     fprintf (stderr, _("Try `%s --help' for more information.\n"),
73              program_name);
74   else
75     {
76       printf (_("Usage: %s [OPTION]... [STRING]...\n"), program_name);
77       fputs (_("\
78 Echo the STRING(s) to standard output.\n\
79 \n\
80   -n              do not output the trailing newline\n\
81   -e              enable interpretation of the backslash-escaped characters\n\
82                     listed below\n\
83   -E              disable interpretation of those sequences in STRINGs\n\
84 "), stdout);
85       fputs (HELP_OPTION_DESCRIPTION, stdout);
86       fputs (VERSION_OPTION_DESCRIPTION, stdout);
87       fputs (_("\
88 \n\
89 Without -E, the following sequences are recognized and interpolated:\n\
90 \n\
91   \\NNN   the character whose ASCII code is NNN (octal)\n\
92   \\\\     backslash\n\
93   \\a     alert (BEL)\n\
94   \\b     backspace\n\
95 "), stdout);
96       fputs (_("\
97   \\c     suppress trailing newline\n\
98   \\f     form feed\n\
99   \\n     new line\n\
100   \\r     carriage return\n\
101   \\t     horizontal tab\n\
102   \\v     vertical tab\n\
103 "), stdout);
104       printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
105     }
106   exit (status);
107 }
108
109 /* Print the words in LIST to standard output.  If the first word is
110    `-n', then don't print a trailing newline.  We also support the
111    echo syntax from Version 9 unix systems. */
112
113 int
114 main (int argc, char **argv)
115 {
116   int display_return = 1, do_v9 = 0;
117   int allow_options = 1;
118
119   initialize_main (&argc, &argv);
120   program_name = argv[0];
121   setlocale (LC_ALL, "");
122   bindtextdomain (PACKAGE, LOCALEDIR);
123   textdomain (PACKAGE);
124
125   atexit (close_stdout);
126
127   /* Don't recognize --help or --version if POSIXLY_CORRECT is set.  */
128   if (getenv ("POSIXLY_CORRECT") == NULL)
129     parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
130                       WRITTEN_BY, usage);
131   else
132     allow_options = 0;
133
134 /* System V machines already have a /bin/sh with a v9 behaviour.  We
135    use the identical behaviour for these machines so that the
136    existing system shell scripts won't barf. */
137 #if defined (V9_ECHO) && defined (V9_DEFAULT)
138   do_v9 = allow_options;
139 #endif
140
141   --argc;
142   ++argv;
143
144   while (argc > 0 && *argv[0] == '-')
145     {
146       register char *temp;
147       register int i;
148
149       /* If it appears that we are handling options, then make sure that
150          all of the options specified are actually valid.  Otherwise, the
151          string should just be echoed. */
152       temp = argv[0] + 1;
153
154       for (i = 0; temp[i]; i++)
155         {
156           if (strrchr (VALID_ECHO_OPTIONS, temp[i]) == 0)
157             goto just_echo;
158         }
159
160       if (!*temp)
161         goto just_echo;
162
163       /* All of the options in TEMP are valid options to ECHO.
164          Handle them. */
165       while (*temp)
166         {
167           if (allow_options && *temp == 'n')
168             display_return = 0;
169 #if defined (V9_ECHO)
170           else if (allow_options && *temp == 'e')
171             do_v9 = 1;
172 # if defined (V9_DEFAULT)
173           else if (allow_options && *temp == 'E')
174             do_v9 = 0;
175 # endif /* V9_DEFAULT */
176 #endif /* V9_ECHO */
177           else
178             goto just_echo;
179
180           temp++;
181         }
182       argc--;
183       argv++;
184     }
185
186 just_echo:
187
188   if (argc > 0)
189     {
190 #if defined (V9_ECHO)
191       if (do_v9)
192         {
193           while (argc > 0)
194             {
195               register char *s = argv[0];
196               register int c;
197
198               while ((c = *s++))
199                 {
200                   if (c == '\\' && *s)
201                     {
202                       switch (c = *s++)
203                         {
204                         case 'a': c = '\007'; break;
205                         case 'b': c = '\b'; break;
206                         case 'c': display_return = 0; continue;
207                         case 'f': c = '\f'; break;
208                         case 'n': c = '\n'; break;
209                         case 'r': c = '\r'; break;
210                         case 't': c = '\t'; break;
211                         case 'v': c = (int) 0x0B; break;
212                         case '0': case '1': case '2': case '3':
213                         case '4': case '5': case '6': case '7':
214                           c -= '0';
215                           if (*s >= '0' && *s <= '7')
216                             c = c * 8 + (*s++ - '0');
217                           if (*s >= '0' && *s <= '7')
218                             c = c * 8 + (*s++ - '0');
219                           break;
220                         case '\\': break;
221                         default:  putchar ('\\'); break;
222                         }
223                     }
224                   putchar(c);
225                 }
226               argc--;
227               argv++;
228               if (argc > 0)
229                 putchar(' ');
230             }
231         }
232       else
233 #endif /* V9_ECHO */
234         {
235           while (argc > 0)
236             {
237               fputs (argv[0], stdout);
238               argc--;
239               argv++;
240               if (argc > 0)
241                 putchar (' ');
242             }
243         }
244     }
245   if (display_return)
246     putchar ('\n');
247   exit (EXIT_SUCCESS);
248 }