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