maint: revert "build: update gnulib submodule to latest"
[coreutils/ericb.git] / src / echo.c
blob666f1cc8b7d56345083668cedcd668adc69b62a8
1 /* echo.c, derived from code echo.c in Bash.
2 Copyright (C) 1987, 1989, 1991-1997, 1999-2005, 2007-2011 Free Software
3 Foundation, Inc.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */
18 #include <config.h>
19 #include <stdio.h>
20 #include <sys/types.h>
21 #include "system.h"
23 /* The official name of this program (e.g., no `g' prefix). */
24 #define PROGRAM_NAME "echo"
26 #define AUTHORS \
27 proper_name ("Brian Fox"), \
28 proper_name ("Chet Ramey")
30 /* If true, interpret backslash escapes by default. */
31 #ifndef DEFAULT_ECHO_TO_XPG
32 enum { DEFAULT_ECHO_TO_XPG = false };
33 #endif
35 void
36 usage (int status)
38 if (status != EXIT_SUCCESS)
39 fprintf (stderr, _("Try `%s --help' for more information.\n"),
40 program_name);
41 else
43 printf (_("\
44 Usage: %s [SHORT-OPTION]... [STRING]...\n\
45 or: %s LONG-OPTION\n\
46 "), program_name, program_name);
47 fputs (_("\
48 Echo the STRING(s) to standard output.\n\
49 \n\
50 -n do not output the trailing newline\n\
51 "), stdout);
52 fputs (_(DEFAULT_ECHO_TO_XPG
53 ? N_("\
54 -e enable interpretation of backslash escapes (default)\n\
55 -E disable interpretation of backslash escapes\n")
56 : N_("\
57 -e enable interpretation of backslash escapes\n\
58 -E disable interpretation of backslash escapes (default)\n")),
59 stdout);
60 fputs (HELP_OPTION_DESCRIPTION, stdout);
61 fputs (VERSION_OPTION_DESCRIPTION, stdout);
62 fputs (_("\
63 \n\
64 If -e is in effect, the following sequences are recognized:\n\
65 \n\
66 "), stdout);
67 fputs (_("\
68 \\\\ backslash\n\
69 \\a alert (BEL)\n\
70 \\b backspace\n\
71 \\c produce no further output\n\
72 \\e escape\n\
73 \\f form feed\n\
74 \\n new line\n\
75 \\r carriage return\n\
76 \\t horizontal tab\n\
77 \\v vertical tab\n\
78 "), stdout);
79 fputs (_("\
80 \\0NNN byte with octal value NNN (1 to 3 digits)\n\
81 \\xHH byte with hexadecimal value HH (1 to 2 digits)\n\
82 "), stdout);
83 printf (USAGE_BUILTIN_WARNING, PROGRAM_NAME);
84 emit_ancillary_info ();
86 exit (status);
89 /* Convert C from hexadecimal character to integer. */
90 static int
91 hextobin (unsigned char c)
93 switch (c)
95 default: return c - '0';
96 case 'a': case 'A': return 10;
97 case 'b': case 'B': return 11;
98 case 'c': case 'C': return 12;
99 case 'd': case 'D': return 13;
100 case 'e': case 'E': return 14;
101 case 'f': case 'F': return 15;
105 /* Print the words in LIST to standard output. If the first word is
106 `-n', then don't print a trailing newline. We also support the
107 echo syntax from Version 9 unix systems. */
110 main (int argc, char **argv)
112 bool display_return = true;
113 bool allow_options =
114 (! getenv ("POSIXLY_CORRECT")
115 || (! DEFAULT_ECHO_TO_XPG && 1 < argc && STREQ (argv[1], "-n")));
117 /* System V machines already have a /bin/sh with a v9 behavior.
118 Use the identical behavior for these machines so that the
119 existing system shell scripts won't barf. */
120 bool do_v9 = DEFAULT_ECHO_TO_XPG;
122 initialize_main (&argc, &argv);
123 set_program_name (argv[0]);
124 setlocale (LC_ALL, "");
125 bindtextdomain (PACKAGE, LOCALEDIR);
126 textdomain (PACKAGE);
128 atexit (close_stdout);
130 /* We directly parse options, rather than use parse_long_options, in
131 order to avoid accepting abbreviations. */
132 if (allow_options && argc == 2)
134 if (STREQ (argv[1], "--help"))
135 usage (EXIT_SUCCESS);
137 if (STREQ (argv[1], "--version"))
139 version_etc (stdout, PROGRAM_NAME, PACKAGE_NAME, Version, AUTHORS,
140 (char *) NULL);
141 exit (EXIT_SUCCESS);
145 --argc;
146 ++argv;
148 if (allow_options)
149 while (argc > 0 && *argv[0] == '-')
151 char const *temp = argv[0] + 1;
152 size_t i;
154 /* If it appears that we are handling options, then make sure that
155 all of the options specified are actually valid. Otherwise, the
156 string should just be echoed. */
158 for (i = 0; temp[i]; i++)
159 switch (temp[i])
161 case 'e': case 'E': case 'n':
162 break;
163 default:
164 goto just_echo;
167 if (i == 0)
168 goto just_echo;
170 /* All of the options in TEMP are valid options to ECHO.
171 Handle them. */
172 while (*temp)
173 switch (*temp++)
175 case 'e':
176 do_v9 = true;
177 break;
179 case 'E':
180 do_v9 = false;
181 break;
183 case 'n':
184 display_return = false;
185 break;
188 argc--;
189 argv++;
192 just_echo:
194 if (do_v9)
196 while (argc > 0)
198 char const *s = argv[0];
199 unsigned char c;
201 while ((c = *s++))
203 if (c == '\\' && *s)
205 switch (c = *s++)
207 case 'a': c = '\a'; break;
208 case 'b': c = '\b'; break;
209 case 'c': exit (EXIT_SUCCESS);
210 case 'e': c = '\x1B'; break;
211 case 'f': c = '\f'; break;
212 case 'n': c = '\n'; break;
213 case 'r': c = '\r'; break;
214 case 't': c = '\t'; break;
215 case 'v': c = '\v'; break;
216 case 'x':
218 unsigned char ch = *s;
219 if (! isxdigit (ch))
220 goto not_an_escape;
221 s++;
222 c = hextobin (ch);
223 ch = *s;
224 if (isxdigit (ch))
226 s++;
227 c = c * 16 + hextobin (ch);
230 break;
231 case '0':
232 c = 0;
233 if (! ('0' <= *s && *s <= '7'))
234 break;
235 c = *s++;
236 /* Fall through. */
237 case '1': case '2': case '3':
238 case '4': case '5': case '6': case '7':
239 c -= '0';
240 if ('0' <= *s && *s <= '7')
241 c = c * 8 + (*s++ - '0');
242 if ('0' <= *s && *s <= '7')
243 c = c * 8 + (*s++ - '0');
244 break;
245 case '\\': break;
247 not_an_escape:
248 default: putchar ('\\'); break;
251 putchar (c);
253 argc--;
254 argv++;
255 if (argc > 0)
256 putchar (' ');
259 else
261 while (argc > 0)
263 fputs (argv[0], stdout);
264 argc--;
265 argv++;
266 if (argc > 0)
267 putchar (' ');
271 if (display_return)
272 putchar ('\n');
273 exit (EXIT_SUCCESS);