source: trunk/coreutils/src/echo.c@ 2555

Last change on this file since 2555 was 2554, checked in by bird, 20 years ago

coretuils-5.94

File size: 6.6 KB
Line 
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 ...]
30Output the ARGs. If -n is specified, the trailing newline is
31suppressed. If the -e option is given, interpretation of the
32following 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
44You can explicitly turn off the interpretation of the above characters
45on System V systems with the -E option.
46*/
47
48/* If true, interpret backslash escapes by default. */
49#ifndef DEFAULT_ECHO_TO_XPG
50enum { DEFAULT_ECHO_TO_XPG = false };
51#endif
52
53/* The name this program was run with. */
54char *program_name;
55
56void
57usage (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 (_("\
66Echo 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\
82If -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. */
104static int
105hextobin (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
123int
124main (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
195just_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}
Note: See TracBrowser for help on using the repository browser.