| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #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; |
| | } |
| |
|