* NEWS: Add a line for 6.5-cvs.
[coreutils.git] / src / echo.c
blob5f8582cc0fe14c964d569e0bdca8fdd3b085892d
1 /* echo.c, derived from code echo.c in Bash.
2 Copyright (C) 87,89, 1991-1997, 1999-2005 Free Software Foundation, Inc.
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.
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.
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. */
18 #include <config.h>
19 #include <stdio.h>
20 #include <sys/types.h>
21 #include "system.h"
22 #include "long-options.h"
24 /* The official name of this program (e.g., no `g' prefix). */
25 #define PROGRAM_NAME "echo"
27 #define AUTHORS "FIXME unknown"
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).
44 You can explicitly turn off the interpretation of the above characters
45 on System V systems with the -E option.
48 /* If true, interpret backslash escapes by default. */
49 #ifndef DEFAULT_ECHO_TO_XPG
50 enum { DEFAULT_ECHO_TO_XPG = false };
51 #endif
53 /* The name this program was run with. */
54 char *program_name;
56 void
57 usage (int status)
59 if (status != EXIT_SUCCESS)
60 fprintf (stderr, _("Try `%s --help' for more information.\n"),
61 program_name);
62 else
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);
100 exit (status);
103 /* Convert C from hexadecimal character to integer. */
104 static int
105 hextobin (unsigned char c)
107 switch (c)
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;
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. */
124 main (int argc, char **argv)
126 bool display_return = true;
127 bool allow_options =
128 (! getenv ("POSIXLY_CORRECT")
129 || (! DEFAULT_ECHO_TO_XPG && 1 < argc && STREQ (argv[1], "-n")));
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;
136 initialize_main (&argc, &argv);
137 program_name = argv[0];
138 setlocale (LC_ALL, "");
139 bindtextdomain (PACKAGE, LOCALEDIR);
140 textdomain (PACKAGE);
142 atexit (close_stdout);
144 if (allow_options)
145 parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
146 usage, AUTHORS, (char const *) NULL);
148 --argc;
149 ++argv;
151 if (allow_options)
152 while (argc > 0 && *argv[0] == '-')
154 char const *temp = argv[0] + 1;
155 size_t i;
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. */
161 for (i = 0; temp[i]; i++)
162 switch (temp[i])
164 case 'e': case 'E': case 'n':
165 break;
166 default:
167 goto just_echo;
170 if (i == 0)
171 goto just_echo;
173 /* All of the options in TEMP are valid options to ECHO.
174 Handle them. */
175 while (*temp)
176 switch (*temp++)
178 case 'e':
179 do_v9 = true;
180 break;
182 case 'E':
183 do_v9 = false;
184 break;
186 case 'n':
187 display_return = false;
188 break;
191 argc--;
192 argv++;
195 just_echo:
197 if (do_v9)
199 while (argc > 0)
201 char const *s = argv[0];
202 unsigned char c;
204 while ((c = *s++))
206 if (c == '\\' && *s)
208 switch (c = *s++)
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':
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))
228 s++;
229 c = c * 16 + hextobin (ch);
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;
249 not_an_escape:
250 default: putchar ('\\'); break;
253 putchar (c);
255 argc--;
256 argv++;
257 if (argc > 0)
258 putchar (' ');
261 else
263 while (argc > 0)
265 fputs (argv[0], stdout);
266 argc--;
267 argv++;
268 if (argc > 0)
269 putchar (' ');
273 if (display_return)
274 putchar ('\n');
275 exit (EXIT_SUCCESS);