| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| #include <config.h> |
| #include <stdio.h> |
| #include <sys/types.h> |
| #include "system.h" |
| #include "assure.h" |
| #include "c-ctype.h" |
|
|
| |
| #define PROGRAM_NAME "echo" |
|
|
| #define AUTHORS \ |
| proper_name ("Brian Fox"), \ |
| proper_name ("Chet Ramey") |
|
|
| |
| #ifndef DEFAULT_ECHO_TO_XPG |
| enum { DEFAULT_ECHO_TO_XPG = false }; |
| #endif |
|
|
| void |
| usage (int status) |
| { |
| |
| |
| affirm (status == EXIT_SUCCESS); |
|
|
| printf (_("\ |
| Usage: %s [SHORT-OPTION]... [STRING]...\n\ |
| or: %s LONG-OPTION\n\ |
| "), program_name, program_name); |
| fputs (_("\ |
| Echo the STRING(s) to standard output.\n\ |
| \n\ |
| -n do not output the trailing newline\n\ |
| "), stdout); |
| fputs (_(DEFAULT_ECHO_TO_XPG |
| ? N_("\ |
| -e enable interpretation of backslash escapes (default)\n\ |
| -E disable interpretation of backslash escapes\n") |
| : N_("\ |
| -e enable interpretation of backslash escapes\n\ |
| -E disable interpretation of backslash escapes (default)\n")), |
| stdout); |
| fputs (HELP_OPTION_DESCRIPTION, stdout); |
| fputs (VERSION_OPTION_DESCRIPTION, stdout); |
| fputs (_("\ |
| \n\ |
| If -e is in effect, the following sequences are recognized:\n\ |
| \n\ |
| "), stdout); |
| fputs (_("\ |
| \\\\ backslash\n\ |
| \\a alert (BEL)\n\ |
| \\b backspace\n\ |
| \\c produce no further output\n\ |
| \\e escape\n\ |
| \\f form feed\n\ |
| \\n new line\n\ |
| \\r carriage return\n\ |
| \\t horizontal tab\n\ |
| \\v vertical tab\n\ |
| "), stdout); |
| fputs (_("\ |
| \\0NNN byte with octal value NNN (1 to 3 digits)\n\ |
| \\xHH byte with hexadecimal value HH (1 to 2 digits)\n\ |
| "), stdout); |
| printf (USAGE_BUILTIN_WARNING, PROGRAM_NAME); |
| fputs (_("\n\ |
| Consider using the printf(1) command instead,\n\ |
| as it avoids problems when outputting option-like strings.\n\ |
| "), stdout); |
| emit_ancillary_info (PROGRAM_NAME); |
| exit (status); |
| } |
|
|
| |
| static int |
| hextobin (unsigned char c) |
| { |
| switch (c) |
| { |
| default: return c - '0'; |
| case 'a': case 'A': return 10; |
| case 'b': case 'B': return 11; |
| case 'c': case 'C': return 12; |
| case 'd': case 'D': return 13; |
| case 'e': case 'E': return 14; |
| case 'f': case 'F': return 15; |
| } |
| } |
|
|
| |
| |
| |
|
|
| int |
| main (int argc, char **argv) |
| { |
| bool display_return = true; |
| bool posixly_correct = !!getenv ("POSIXLY_CORRECT"); |
| bool allow_options = |
| (! posixly_correct |
| || (! DEFAULT_ECHO_TO_XPG && 1 < argc && streq (argv[1], "-n"))); |
|
|
| |
| |
| |
| bool do_v9 = DEFAULT_ECHO_TO_XPG; |
|
|
| initialize_main (&argc, &argv); |
| set_program_name (argv[0]); |
| setlocale (LC_ALL, ""); |
| bindtextdomain (PACKAGE, LOCALEDIR); |
| textdomain (PACKAGE); |
|
|
| atexit (close_stdout); |
|
|
| |
| |
| if (allow_options && argc == 2) |
| { |
| if (streq (argv[1], "--help")) |
| usage (EXIT_SUCCESS); |
|
|
| if (streq (argv[1], "--version")) |
| { |
| version_etc (stdout, PROGRAM_NAME, PACKAGE_NAME, Version, AUTHORS, |
| (char *) nullptr); |
| return EXIT_SUCCESS; |
| } |
| } |
|
|
| --argc; |
| ++argv; |
|
|
| if (allow_options) |
| while (argc > 0 && *argv[0] == '-') |
| { |
| char const *temp = argv[0] + 1; |
| size_t i; |
|
|
| |
| |
| |
|
|
| for (i = 0; temp[i]; i++) |
| switch (temp[i]) |
| { |
| case 'e': case 'E': case 'n': |
| break; |
| default: |
| goto just_echo; |
| } |
|
|
| if (i == 0) |
| goto just_echo; |
|
|
| |
| |
| while (*temp) |
| switch (*temp++) |
| { |
| case 'e': |
| do_v9 = true; |
| break; |
|
|
| case 'E': |
| do_v9 = false; |
| break; |
|
|
| case 'n': |
| display_return = false; |
| break; |
| } |
|
|
| argc--; |
| argv++; |
| } |
|
|
| just_echo: |
|
|
| if (do_v9 || posixly_correct) |
| { |
| while (argc > 0) |
| { |
| char const *s = argv[0]; |
| unsigned char c; |
|
|
| while ((c = *s++)) |
| { |
| if (c == '\\' && *s) |
| { |
| switch (c = *s++) |
| { |
| case 'a': c = '\a'; break; |
| case 'b': c = '\b'; break; |
| case 'c': return EXIT_SUCCESS; |
| case 'e': c = '\x1B'; break; |
| case 'f': c = '\f'; break; |
| case 'n': c = '\n'; break; |
| case 'r': c = '\r'; break; |
| case 't': c = '\t'; break; |
| case 'v': c = '\v'; break; |
| case 'x': |
| { |
| unsigned char ch = *s; |
| if (! c_isxdigit (ch)) |
| goto not_an_escape; |
| s++; |
| c = hextobin (ch); |
| ch = *s; |
| if (c_isxdigit (ch)) |
| { |
| s++; |
| c = c * 16 + hextobin (ch); |
| } |
| } |
| break; |
| case '0': |
| c = 0; |
| if (! ('0' <= *s && *s <= '7')) |
| break; |
| c = *s++; |
| FALLTHROUGH; |
| case '1': case '2': case '3': |
| case '4': case '5': case '6': case '7': |
| c -= '0'; |
| if ('0' <= *s && *s <= '7') |
| c = c * 8 + (*s++ - '0'); |
| if ('0' <= *s && *s <= '7') |
| c = c * 8 + (*s++ - '0'); |
| break; |
| case '\\': break; |
|
|
| not_an_escape: |
| default: putchar ('\\'); break; |
| } |
| } |
| putchar (c); |
| } |
| argc--; |
| argv++; |
| if (argc > 0) |
| putchar (' '); |
| } |
| } |
| else |
| { |
| while (argc > 0) |
| { |
| fputs (argv[0], stdout); |
| argc--; |
| argv++; |
| if (argc > 0) |
| putchar (' '); |
| } |
| } |
|
|
| if (display_return) |
| putchar ('\n'); |
| return EXIT_SUCCESS; |
| } |
|
|