/* echo.c, derived from code echo.c in Bash. This is the echo utility
Copyright (C) 1987-2018 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */ The GNUv3 license
#include <config.h> Provides system specific information
#include <stdio.h> Provides standard I/O capability
#include <sys/types.h> Provides system data types
#include "system.h" ...!includes auto-comment...
/* The official name of this program (e.g., no 'g' prefix). */
#define PROGRAM_NAME "echo" Line 23
#define AUTHORS \ Line 25
proper_name ("Brian Fox"), \ Line 26
proper_name ("Chet Ramey") Line 27
/* If true, interpret backslash escapes by default. */
#ifndef DEFAULT_ECHO_TO_XPG Line 30
enum { DEFAULT_ECHO_TO_XPG = false }; Line 31Block 1
#endif Line 32
void Line 34
usage (int status) Line 35
{
if (status != EXIT_SUCCESS) Line 37
emit_try_help (); ...!common auto-comment...
else Line 39
{
printf (_("\ Line 41
Usage: %s [SHORT-OPTION]... [STRING]...\n\ Line 42
or: %s LONG-OPTION\n\ Line 43
"), program_name, program_name); Line 44
fputs (_("\ Line 45
Echo the STRING(s) to standard output.\n\ Line 46
\n\
-n do not output the trailing newline\n\ Line 48
"), stdout); Line 49
fputs (_(DEFAULT_ECHO_TO_XPG Line 50
? N_("\ Line 51
-e enable interpretation of backslash escapes (default)\n\ Line 52
-E disable interpretation of backslash escapes\n") Line 53
: N_("\ Line 54
-e enable interpretation of backslash escapes\n\ Line 55
-E disable interpretation of backslash escapes (default)\n")), Line 56
stdout); Line 57
fputs (HELP_OPTION_DESCRIPTION, stdout); Line 58
fputs (VERSION_OPTION_DESCRIPTION, stdout); Line 59
fputs (_("\ Line 60
\n\
If -e is in effect, the following sequences are recognized:\n\ Line 62
\n\
"), stdout); Line 64
fputs (_("\ Line 65
\\\\ backslash\n\ Line 66
\\a alert (BEL)\n\ Line 67
\\b backspace\n\ Line 68
\\c produce no further output\n\ Line 69
\\e escape\n\ Line 70
\\f form feed\n\ Line 71
\\n new line\n\ Line 72
\\r carriage return\n\ Line 73
\\t horizontal tab\n\ Line 74
\\v vertical tab\n\ Line 75
"), stdout); Line 76
fputs (_("\ Line 77
\\0NNN byte with octal value NNN (1 to 3 digits)\n\ Line 78
\\xHH byte with hexadecimal value HH (1 to 2 digits)\n\ Line 79
"), stdout); Line 80
printf (USAGE_BUILTIN_WARNING, PROGRAM_NAME); Line 81
emit_ancillary_info (PROGRAM_NAME); Line 82
}
exit (status); Line 84
} Block 2
/* Convert C from hexadecimal character to integer. */
static int Line 88
hextobin (unsigned char c) Line 89
{
switch (c) Line 91
{
default: return c - '0'; Line 93
case 'a': case 'A': return 10; Line 94
case 'b': case 'B': return 11; Line 95
case 'c': case 'C': return 12; Line 96
case 'd': case 'D': return 13; Line 97
case 'e': case 'E': return 14; Line 98
case 'f': case 'F': return 15; Line 99
}
} Block 3
/* Print the words in LIST to standard output. If the first word is
'-n', then don't print a trailing newline. We also support the
echo syntax from Version 9 unix systems. */
int
main (int argc, char **argv) Line 108
{
bool display_return = true; Line 110
bool allow_options = Line 111
(! getenv ("POSIXLY_CORRECT") Line 112
|| (! DEFAULT_ECHO_TO_XPG && 1 < argc && STREQ (argv[1], "-n"))); Line 113
/* System V machines already have a /bin/sh with a v9 behavior.
Use the identical behavior for these machines so that the
existing system shell scripts won't barf. */
bool do_v9 = DEFAULT_ECHO_TO_XPG; Line 118
initialize_main (&argc, &argv); VMS-specific entry point handling wildcard expansion
set_program_name (argv[0]); Retains program name and discards path
setlocale (LC_ALL, ""); Sets up internationalization (i18n)
bindtextdomain (PACKAGE, LOCALEDIR); Assigns i18n directorySets text domain for _() [gettext()] function
textdomain (PACKAGE); Sets text domain for _() [gettext()] function
atexit (close_stdout); Close stdout on exit (see gnulib)
/* We directly parse options, rather than use parse_long_options, in
order to avoid accepting abbreviations. */
if (allow_options && argc == 2) Line 130
{
if (STREQ (argv[1], "--help")) Line 132
usage (EXIT_SUCCESS); Line 133
if (STREQ (argv[1], "--version")) Line 135
{
version_etc (stdout, PROGRAM_NAME, PACKAGE_NAME, Version, AUTHORS, Line 137
(char *) NULL); Line 138
return EXIT_SUCCESS; Line 139
}
}
--argc; Line 143
++argv; Line 144
if (allow_options) Line 146
while (argc > 0 && *argv[0] == '-') Line 147
{
char const *temp = argv[0] + 1; Line 149
size_t i; Line 150
/* If it appears that we are handling options, then make sure that
all of the options specified are actually valid. Otherwise, the
string should just be echoed. */
for (i = 0; temp[i]; i++) Line 156
switch (temp[i]) Line 157
{
case 'e': case 'E': case 'n': Line 159
break; Line 160
default: Line 161
goto just_echo; Line 162
}
if (i == 0) Line 165
goto just_echo; Line 166
/* All of the options in TEMP are valid options to ECHO.
Handle them. */
while (*temp) Line 170
switch (*temp++) Line 171
{
case 'e': Line 173
do_v9 = true; Line 174
break; Line 175
case 'E': Line 177
do_v9 = false; Line 178
break; Line 179
case 'n': Line 181
display_return = false; Line 182
break; Line 183
}
argc--; Line 186
argv++; Line 187
}
just_echo: Line 190
if (do_v9) Line 192
{
while (argc > 0) Line 194
{
char const *s = argv[0]; Line 196
unsigned char c; Line 197
while ((c = *s++)) Line 199
{
if (c == '\\' && *s) Line 201
{
switch (c = *s++) Line 203
{
case 'a': c = '\a'; break; Line 205
case 'b': c = '\b'; break; Line 206
case 'c': return EXIT_SUCCESS; Line 207
case 'e': c = '\x1B'; break; Line 208
case 'f': c = '\f'; break; Line 209
case 'n': c = '\n'; break; Line 210
case 'r': c = '\r'; break; Line 211
case 't': c = '\t'; break; Line 212
case 'v': c = '\v'; break; Line 213
case 'x': Line 214
{
unsigned char ch = *s; Line 216
if (! isxdigit (ch)) Line 217
goto not_an_escape; Line 218
s++; Line 219
c = hextobin (ch); Line 220
ch = *s; Line 221
if (isxdigit (ch)) Line 222
{
s++; Line 224
c = c * 16 + hextobin (ch); Line 225
}
}
break; Line 228
case '0': Line 229
c = 0; Line 230
if (! ('0' <= *s && *s <= '7')) Line 231
break; Line 232
c = *s++; Line 233
FALLTHROUGH; Line 234
case '1': case '2': case '3': Line 235
case '4': case '5': case '6': case '7': Line 236
c -= '0'; Line 237
if ('0' <= *s && *s <= '7') Line 238
c = c * 8 + (*s++ - '0'); Line 239
if ('0' <= *s && *s <= '7') Line 240
c = c * 8 + (*s++ - '0'); Line 241
break; Line 242
case '\\': break; Line 243
not_an_escape: Line 245
default: putchar ('\\'); break; Line 246
}
}
putchar (c); Line 249
}
argc--; Line 251
argv++; Line 252
if (argc > 0) Line 253
putchar (' '); Line 254
}
}
else Line 257
{
while (argc > 0) Line 259
{
fputs (argv[0], stdout); Line 261
argc--; Line 262
argv++; Line 263
if (argc > 0) Line 264
putchar (' '); Line 265
}
}
if (display_return) Line 269
putchar ('\n'); Line 270
return EXIT_SUCCESS; Line 271
} Block 4