(root)/
sed-4.9/
sed/
sed.c
       1  /*  GNU SED, a batch stream editor.
       2      Copyright (C) 1989-2022 Free Software Foundation, Inc.
       3  
       4      This program is free software; you can redistribute it and/or modify
       5      it under the terms of the GNU General Public License as published by
       6      the Free Software Foundation; either version 3, or (at your option)
       7      any later version.
       8  
       9      This program is distributed in the hope that it will be useful,
      10      but WITHOUT ANY WARRANTY; without even the implied warranty of
      11      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12      GNU General Public License for more details.
      13  
      14      You should have received a copy of the GNU General Public License
      15      along with this program; If not, see <https://www.gnu.org/licenses/>. */
      16  
      17  
      18  #include "sed.h"
      19  
      20  
      21  #include <limits.h>
      22  #include <stdio.h>
      23  #include <string.h>
      24  #include <stdlib.h>
      25  #include <sys/types.h>
      26  #include <unistd.h>
      27  #include "binary-io.h"
      28  #include "getopt.h"
      29  #include "progname.h"
      30  #include "version.h"
      31  #include "xalloc.h"
      32  #include <selinux/selinux.h>
      33  
      34  #include "version-etc.h"
      35  
      36  #define AUTHORS \
      37     _("Jay Fenlason"), \
      38     _("Tom Lord"), \
      39     _("Ken Pizzini"), \
      40     _("Paolo Bonzini"), \
      41     _("Jim Meyering"), \
      42     _("Assaf Gordon")
      43  
      44  int extended_regexp_flags = 0;
      45  
      46  /* one-byte buffer delimiter */
      47  char buffer_delimiter = '\n';
      48  
      49  /* If set, fflush(stdout) on every line output. */
      50  bool unbuffered = false;
      51  
      52  /* If set, don't write out the line unless explicitly told to */
      53  bool no_default_output = false;
      54  
      55  /* If set, reset line counts on every new file. */
      56  bool separate_files = false;
      57  
      58  /* If set, follow symlinks when processing in place */
      59  bool follow_symlinks = false;
      60  
      61  /* If set, opearate in 'sandbox' mode */
      62  bool sandbox = false;
      63  
      64  /* if set, print debugging information */
      65  bool debug = false;
      66  
      67  /* How do we edit files in-place? (we don't if NULL) */
      68  char *in_place_extension = NULL;
      69  
      70  /* The mode to use to read/write files, either "r"/"w" or "rb"/"wb".  */
      71  char const *read_mode = "r";
      72  char const *write_mode = "w";
      73  
      74  #if O_BINARY
      75  /* Additional flag for binary mode on platforms with O_BINARY/O_TEXT.  */
      76  bool binary_mode = false;
      77  #endif
      78  
      79  /* Do we need to be pedantically POSIX compliant? */
      80  enum posixicity_types posixicity;
      81  
      82  /* How long should the `l' command's output line be? */
      83  countT lcmd_out_line_len = 70;
      84  
      85  /* The complete compiled SED program that we are going to run: */
      86  static struct vector *the_program = NULL;
      87  
      88  struct localeinfo localeinfo;
      89  
      90  /* When exiting between temporary file creation and the rename
      91     associated with a sed -i invocation, remove that file.  */
      92  static void
      93  cleanup (void)
      94  {
      95    IF_LINT (free (in_place_extension));
      96    remove_cleanup_file ();
      97  }
      98  
      99  static void
     100  contact (int errmsg)
     101  {
     102    FILE *out = errmsg ? stderr : stdout;
     103    fprintf (out, _("GNU sed home page: <https://www.gnu.org/software/sed/>.\n\
     104  General help using GNU software: <https://www.gnu.org/gethelp/>.\n"));
     105  
     106    /* Only print the bug report address for `sed --help', otherwise we'll
     107       get reports for other people's bugs.  */
     108    if (!errmsg)
     109      fprintf (out, _("E-mail bug reports to: <%s>.\n"), PACKAGE_BUGREPORT);
     110  }
     111  
     112  static void
     113  selinux_support (void)
     114  {
     115    putchar ('\n');
     116  #if HAVE_SELINUX_SELINUX_H
     117    puts (_("This sed program was built with SELinux support."));
     118    if (is_selinux_enabled ())
     119      puts (_("SELinux is enabled on this system."));
     120    else
     121      puts (_("SELinux is disabled on this system."));
     122  #else
     123    puts (_("This sed program was built without SELinux support."));
     124  #endif
     125    putchar ('\n');
     126  }
     127  
     128  _Noreturn static void
     129  usage (int status)
     130  {
     131    FILE *out = status ? stderr : stdout;
     132  
     133    fprintf (out, _("\
     134  Usage: %s [OPTION]... {script-only-if-no-other-script} [input-file]...\n\
     135  \n"), program_name);
     136  
     137    fprintf (out, _("  -n, --quiet, --silent\n\
     138                   suppress automatic printing of pattern space\n"));
     139    fprintf (out, _("      --debug\n\
     140                   annotate program execution\n"));
     141    fprintf (out, _("  -e script, --expression=script\n\
     142                   add the script to the commands to be executed\n"));
     143    fprintf (out, _("  -f script-file, --file=script-file\n\
     144                   add the contents of script-file to the commands" \
     145                   " to be executed\n"));
     146  #ifdef HAVE_READLINK
     147    fprintf (out, _("  --follow-symlinks\n\
     148                   follow symlinks when processing in place\n"));
     149  #endif
     150    fprintf (out, _("  -i[SUFFIX], --in-place[=SUFFIX]\n\
     151                   edit files in place (makes backup if SUFFIX supplied)\n"));
     152  #if O_BINARY
     153    fprintf (out, _("  -b, --binary\n\
     154                   open files in binary mode (CR+LFs are not" \
     155                   " processed specially)\n"));
     156  #endif
     157    fprintf (out, _("  -l N, --line-length=N\n\
     158                   specify the desired line-wrap length for the `l' command\n"));
     159    fprintf (out, _("  --posix\n\
     160                   disable all GNU extensions.\n"));
     161    fprintf (out, _("  -E, -r, --regexp-extended\n\
     162                   use extended regular expressions in the script\n\
     163                   (for portability use POSIX -E).\n"));
     164    fprintf (out, _("  -s, --separate\n\
     165                   consider files as separate rather than as a single,\n\
     166                   continuous long stream.\n"));
     167    fprintf (out, _("      --sandbox\n\
     168                   operate in sandbox mode (disable e/r/w commands).\n"));
     169    fprintf (out, _("  -u, --unbuffered\n\
     170                   load minimal amounts of data from the input files and flush\n\
     171                   the output buffers more often\n"));
     172    fprintf (out, _("  -z, --null-data\n\
     173                   separate lines by NUL characters\n"));
     174    fprintf (out, _("      --help     display this help and exit\n"));
     175    fprintf (out, _("      --version  output version information and exit\n"));
     176    fprintf (out, _("\n\
     177  If no -e, --expression, -f, or --file option is given, then the first\n\
     178  non-option argument is taken as the sed script to interpret.  All\n\
     179  remaining arguments are names of input files; if no input files are\n\
     180  specified, then the standard input is read.\n\
     181  \n"));
     182    contact (status);
     183  
     184    ck_fclose (NULL);
     185    exit (status);
     186  }
     187  
     188  int
     189  main (int argc, char **argv)
     190  {
     191  #define SHORTOPTS "bsnrzuEe:f:l:i::V:"
     192  
     193    enum { SANDBOX_OPTION = CHAR_MAX+1,
     194           DEBUG_OPTION
     195      };
     196  
     197    static const struct option longopts[] = {
     198      {"binary", 0, NULL, 'b'},
     199      {"regexp-extended", 0, NULL, 'r'},
     200      {"debug", 0, NULL, DEBUG_OPTION},
     201      {"expression", 1, NULL, 'e'},
     202      {"file", 1, NULL, 'f'},
     203      {"in-place", 2, NULL, 'i'},
     204      {"line-length", 1, NULL, 'l'},
     205      {"null-data", 0, NULL, 'z'},
     206      {"zero-terminated", 0, NULL, 'z'},
     207      {"quiet", 0, NULL, 'n'},
     208      {"posix", 0, NULL, 'p'},
     209      {"silent", 0, NULL, 'n'},
     210      {"sandbox", 0, NULL, SANDBOX_OPTION},
     211      {"separate", 0, NULL, 's'},
     212      {"unbuffered", 0, NULL, 'u'},
     213      {"version", 0, NULL, 'v'},
     214      {"help", 0, NULL, 'h'},
     215  #ifdef HAVE_READLINK
     216      {"follow-symlinks", 0, NULL, 'F'},
     217  #endif
     218      {NULL, 0, NULL, 0}
     219    };
     220  
     221    int opt;
     222    int return_code;
     223    const char *cols = getenv ("COLS");
     224  
     225    set_program_name (argv[0]);
     226    initialize_main (&argc, &argv);
     227  #if HAVE_SETLOCALE
     228    /* Set locale according to user's wishes.  */
     229    setlocale (LC_ALL, "");
     230  #endif
     231    initialize_mbcs ();
     232    init_localeinfo (&localeinfo);
     233  
     234    /* Arrange to remove any un-renamed temporary file,
     235       upon premature exit.  */
     236    atexit (cleanup);
     237  
     238  #if ENABLE_NLS
     239  
     240    /* Tell program which translations to use and where to find.  */
     241    bindtextdomain (PACKAGE, LOCALEDIR);
     242    textdomain (PACKAGE);
     243  #endif
     244  
     245    if (getenv ("POSIXLY_CORRECT") != NULL)
     246      posixicity = POSIXLY_CORRECT;
     247    else
     248      posixicity = POSIXLY_EXTENDED;
     249  
     250    /* If environment variable `COLS' is set, use its value for
     251       the baseline setting of `lcmd_out_line_len'.  The "-1"
     252       is to avoid gratuitous auto-line-wrap on ttys.
     253     */
     254    if (cols)
     255      {
     256        countT t = atoi (cols);
     257        if (t > 1)
     258          lcmd_out_line_len = t-1;
     259      }
     260  
     261    while ((opt = getopt_long (argc, argv, SHORTOPTS, longopts, NULL)) != EOF)
     262      {
     263        switch (opt)
     264          {
     265          case 'n':
     266            no_default_output = true;
     267            break;
     268          case 'e':
     269            the_program = compile_string (the_program, optarg, strlen (optarg));
     270            break;
     271          case 'f':
     272            the_program = compile_file (the_program, optarg);
     273            break;
     274  
     275          case 'z':
     276            buffer_delimiter = 0;
     277            break;
     278  
     279          case 'F':
     280            follow_symlinks = true;
     281            break;
     282  
     283          case 'i':
     284            separate_files = true;
     285            IF_LINT (free (in_place_extension));
     286            if (optarg == NULL)
     287              /* use no backups */
     288              in_place_extension = xstrdup ("*");
     289  
     290            else if (strchr (optarg, '*') != NULL)
     291              in_place_extension = xstrdup (optarg);
     292  
     293            else
     294              {
     295                in_place_extension = XCALLOC (strlen (optarg) + 2, char);
     296                in_place_extension[0] = '*';
     297                strcpy (in_place_extension + 1, optarg);
     298              }
     299  
     300            break;
     301  
     302          case 'l':
     303            lcmd_out_line_len = atoi (optarg);
     304            break;
     305  
     306          case 'p':
     307            posixicity = POSIXLY_BASIC;
     308            break;
     309  
     310          case 'b':
     311            read_mode = "rb";
     312            write_mode = "wb";
     313  #if O_BINARY
     314            binary_mode = true;
     315  #endif
     316            break;
     317  
     318          case 'E':
     319          case 'r':
     320            extended_regexp_flags = REG_EXTENDED;
     321            break;
     322  
     323          case 's':
     324            separate_files = true;
     325            break;
     326  
     327          case SANDBOX_OPTION:
     328            sandbox = true;
     329            break;
     330  
     331          case DEBUG_OPTION:
     332            debug = true;
     333            break;
     334  
     335          case 'u':
     336            unbuffered = true;
     337            break;
     338  
     339          case 'v':
     340            version_etc (stdout, program_name, PACKAGE_NAME, Version,
     341                        AUTHORS, (char *) NULL);
     342            selinux_support ();
     343            contact (false);
     344            ck_fclose (NULL);
     345            exit (EXIT_SUCCESS);
     346          case 'h':
     347            usage (EXIT_SUCCESS);
     348          default:
     349            usage (EXIT_BAD_USAGE);
     350          }
     351      }
     352  
     353    if (!the_program)
     354      {
     355        if (optind < argc)
     356          {
     357            char *arg = argv[optind++];
     358            the_program = compile_string (the_program, arg, strlen (arg));
     359          }
     360        else
     361          usage (EXIT_BAD_USAGE);
     362      }
     363    check_final_program (the_program);
     364  
     365  #if O_BINARY
     366    if (binary_mode)
     367      {
     368         if (set_binary_mode ( fileno (stdin), O_BINARY) == -1)
     369           panic (_("failed to set binary mode on STDIN"));
     370         if (set_binary_mode ( fileno (stdout), O_BINARY) == -1)
     371           panic (_("failed to set binary mode on STDOUT"));
     372      }
     373  #endif
     374  
     375    if (debug)
     376      debug_print_program (the_program);
     377  
     378    return_code = process_files (the_program, argv+optind);
     379  
     380    finish_program (the_program);
     381    ck_fclose (NULL);
     382  
     383    return return_code;
     384  }