/* 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