summaryrefslogtreecommitdiff
path: root/sed/sed.c
diff options
context:
space:
mode:
Diffstat (limited to 'sed/sed.c')
-rw-r--r--sed/sed.c388
1 files changed, 388 insertions, 0 deletions
diff --git a/sed/sed.c b/sed/sed.c
new file mode 100644
index 0000000..e588c56
--- /dev/null
+++ b/sed/sed.c
@@ -0,0 +1,388 @@
+/* GNU SED, a batch stream editor.
+ Copyright (C) 1989-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, 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/>. */
+
+
+#include "sed.h"
+
+
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "binary-io.h"
+#include "getopt.h"
+#include "progname.h"
+#include "version.h"
+#include "xalloc.h"
+
+#include "version-etc.h"
+
+#define AUTHORS \
+ _("Jay Fenlason"), \
+ _("Tom Lord"), \
+ _("Ken Pizzini"), \
+ _("Paolo Bonzini"), \
+ _("Jim Meyering"), \
+ _("Assaf Gordon")
+
+int extended_regexp_flags = 0;
+
+/* one-byte buffer delimiter */
+char buffer_delimiter = '\n';
+
+/* If set, fflush(stdout) on every line output. */
+bool unbuffered = false;
+
+/* If set, don't write out the line unless explicitly told to */
+bool no_default_output = false;
+
+/* If set, reset line counts on every new file. */
+bool separate_files = false;
+
+/* If set, follow symlinks when processing in place */
+bool follow_symlinks = false;
+
+/* If set, opearate in 'sandbox' mode */
+bool sandbox = false;
+
+/* if set, print debugging information */
+bool debug = false;
+
+/* How do we edit files in-place? (we don't if NULL) */
+char *in_place_extension = NULL;
+
+/* The mode to use to read/write files, either "r"/"w" or "rb"/"wb". */
+char const *read_mode = "r";
+char const *write_mode = "w";
+
+#if O_BINARY
+/* Additional flag for binary mode on platforms with O_BINARY/O_TEXT. */
+bool binary_mode = false;
+#endif
+
+/* Do we need to be pedantically POSIX compliant? */
+enum posixicity_types posixicity;
+
+/* How long should the `l' command's output line be? */
+countT lcmd_out_line_len = 70;
+
+/* The complete compiled SED program that we are going to run: */
+static struct vector *the_program = NULL;
+
+/* When we've created a temporary for an in-place update,
+ we may have to exit before the rename. This is the name
+ of the temporary that we'll have to unlink via an atexit-
+ registered cleanup function. */
+static char const *G_file_to_unlink;
+
+struct localeinfo localeinfo;
+
+/* When exiting between temporary file creation and the rename
+ associated with a sed -i invocation, remove that file. */
+static void
+cleanup (void)
+{
+ IF_LINT (free (in_place_extension));
+ if (G_file_to_unlink)
+ unlink (G_file_to_unlink);
+}
+
+/* Note that FILE must be removed upon exit. */
+void
+register_cleanup_file (char const *file)
+{
+ G_file_to_unlink = file;
+}
+
+/* Clear the global file-to-unlink global. */
+void
+cancel_cleanup (void)
+{
+ G_file_to_unlink = NULL;
+}
+
+static void usage (int);
+static void
+contact (int errmsg)
+{
+ FILE *out = errmsg ? stderr : stdout;
+ fprintf (out, _("GNU sed home page: <https://www.gnu.org/software/sed/>.\n\
+General help using GNU software: <https://www.gnu.org/gethelp/>.\n"));
+
+ /* Only print the bug report address for `sed --help', otherwise we'll
+ get reports for other people's bugs. */
+ if (!errmsg)
+ fprintf (out, _("E-mail bug reports to: <%s>.\n"), PACKAGE_BUGREPORT);
+}
+
+_Noreturn static void
+usage (int status)
+{
+ FILE *out = status ? stderr : stdout;
+
+ fprintf (out, _("\
+Usage: %s [OPTION]... {script-only-if-no-other-script} [input-file]...\n\
+\n"), program_name);
+
+ fprintf (out, _(" -n, --quiet, --silent\n\
+ suppress automatic printing of pattern space\n"));
+ fprintf (out, _(" --debug\n\
+ annotate program execution\n"));
+ fprintf (out, _(" -e script, --expression=script\n\
+ add the script to the commands to be executed\n"));
+ fprintf (out, _(" -f script-file, --file=script-file\n\
+ add the contents of script-file to the commands" \
+ " to be executed\n"));
+#ifdef ENABLE_FOLLOW_SYMLINKS
+ fprintf (out, _(" --follow-symlinks\n\
+ follow symlinks when processing in place\n"));
+#endif
+ fprintf (out, _(" -i[SUFFIX], --in-place[=SUFFIX]\n\
+ edit files in place (makes backup if SUFFIX supplied)\n"));
+#if O_BINARY
+ fprintf (out, _(" -b, --binary\n\
+ open files in binary mode (CR+LFs are not" \
+ " processed specially)\n"));
+#endif
+ fprintf (out, _(" -l N, --line-length=N\n\
+ specify the desired line-wrap length for the `l' command\n"));
+ fprintf (out, _(" --posix\n\
+ disable all GNU extensions.\n"));
+ fprintf (out, _(" -E, -r, --regexp-extended\n\
+ use extended regular expressions in the script\n\
+ (for portability use POSIX -E).\n"));
+ fprintf (out, _(" -s, --separate\n\
+ consider files as separate rather than as a single,\n\
+ continuous long stream.\n"));
+ fprintf (out, _(" --sandbox\n\
+ operate in sandbox mode (disable e/r/w commands).\n"));
+ fprintf (out, _(" -u, --unbuffered\n\
+ load minimal amounts of data from the input files and flush\n\
+ the output buffers more often\n"));
+ fprintf (out, _(" -z, --null-data\n\
+ separate lines by NUL characters\n"));
+ fprintf (out, _(" --help display this help and exit\n"));
+ fprintf (out, _(" --version output version information and exit\n"));
+ fprintf (out, _("\n\
+If no -e, --expression, -f, or --file option is given, then the first\n\
+non-option argument is taken as the sed script to interpret. All\n\
+remaining arguments are names of input files; if no input files are\n\
+specified, then the standard input is read.\n\
+\n"));
+ contact (status);
+
+ ck_fclose (NULL);
+ exit (status);
+}
+
+int
+main (int argc, char **argv)
+{
+#define SHORTOPTS "bsnrzuEe:f:l:i::V:"
+
+ enum { SANDBOX_OPTION = CHAR_MAX+1,
+ DEBUG_OPTION
+ };
+
+ static const struct option longopts[] = {
+ {"binary", 0, NULL, 'b'},
+ {"regexp-extended", 0, NULL, 'r'},
+ {"debug", 0, NULL, DEBUG_OPTION},
+ {"expression", 1, NULL, 'e'},
+ {"file", 1, NULL, 'f'},
+ {"in-place", 2, NULL, 'i'},
+ {"line-length", 1, NULL, 'l'},
+ {"null-data", 0, NULL, 'z'},
+ {"zero-terminated", 0, NULL, 'z'},
+ {"quiet", 0, NULL, 'n'},
+ {"posix", 0, NULL, 'p'},
+ {"silent", 0, NULL, 'n'},
+ {"sandbox", 0, NULL, SANDBOX_OPTION},
+ {"separate", 0, NULL, 's'},
+ {"unbuffered", 0, NULL, 'u'},
+ {"version", 0, NULL, 'v'},
+ {"help", 0, NULL, 'h'},
+#ifdef ENABLE_FOLLOW_SYMLINKS
+ {"follow-symlinks", 0, NULL, 'F'},
+#endif
+ {NULL, 0, NULL, 0}
+ };
+
+ int opt;
+ int return_code;
+ const char *cols = getenv ("COLS");
+
+ set_program_name (argv[0]);
+ initialize_main (&argc, &argv);
+#if HAVE_SETLOCALE
+ /* Set locale according to user's wishes. */
+ setlocale (LC_ALL, "");
+#endif
+ initialize_mbcs ();
+ init_localeinfo (&localeinfo);
+
+ /* Arrange to remove any un-renamed temporary file,
+ upon premature exit. */
+ atexit (cleanup);
+
+#if ENABLE_NLS
+
+ /* Tell program which translations to use and where to find. */
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+#endif
+
+ if (getenv ("POSIXLY_CORRECT") != NULL)
+ posixicity = POSIXLY_CORRECT;
+ else
+ posixicity = POSIXLY_EXTENDED;
+
+ /* If environment variable `COLS' is set, use its value for
+ the baseline setting of `lcmd_out_line_len'. The "-1"
+ is to avoid gratuitous auto-line-wrap on ttys.
+ */
+ if (cols)
+ {
+ countT t = atoi (cols);
+ if (t > 1)
+ lcmd_out_line_len = t-1;
+ }
+
+ while ((opt = getopt_long (argc, argv, SHORTOPTS, longopts, NULL)) != EOF)
+ {
+ switch (opt)
+ {
+ case 'n':
+ no_default_output = true;
+ break;
+ case 'e':
+ the_program = compile_string (the_program, optarg, strlen (optarg));
+ break;
+ case 'f':
+ the_program = compile_file (the_program, optarg);
+ break;
+
+ case 'z':
+ buffer_delimiter = 0;
+ break;
+
+ case 'F':
+ follow_symlinks = true;
+ break;
+
+ case 'i':
+ separate_files = true;
+ IF_LINT (free (in_place_extension));
+ if (optarg == NULL)
+ /* use no backups */
+ in_place_extension = xstrdup ("*");
+
+ else if (strchr (optarg, '*') != NULL)
+ in_place_extension = xstrdup (optarg);
+
+ else
+ {
+ in_place_extension = XCALLOC (strlen (optarg) + 2, char);
+ in_place_extension[0] = '*';
+ strcpy (in_place_extension + 1, optarg);
+ }
+
+ break;
+
+ case 'l':
+ lcmd_out_line_len = atoi (optarg);
+ break;
+
+ case 'p':
+ posixicity = POSIXLY_BASIC;
+ break;
+
+ case 'b':
+ read_mode = "rb";
+ write_mode = "wb";
+#if O_BINARY
+ binary_mode = true;
+#endif
+ break;
+
+ case 'E':
+ case 'r':
+ extended_regexp_flags = REG_EXTENDED;
+ break;
+
+ case 's':
+ separate_files = true;
+ break;
+
+ case SANDBOX_OPTION:
+ sandbox = true;
+ break;
+
+ case DEBUG_OPTION:
+ debug = true;
+ break;
+
+ case 'u':
+ unbuffered = true;
+ break;
+
+ case 'v':
+ version_etc (stdout, program_name, PACKAGE_NAME, Version,
+ AUTHORS, (char *) NULL);
+ contact (false);
+ ck_fclose (NULL);
+ exit (EXIT_SUCCESS);
+ case 'h':
+ usage (EXIT_SUCCESS);
+ default:
+ usage (EXIT_BAD_USAGE);
+ }
+ }
+
+ if (!the_program)
+ {
+ if (optind < argc)
+ {
+ char *arg = argv[optind++];
+ the_program = compile_string (the_program, arg, strlen (arg));
+ }
+ else
+ usage (EXIT_BAD_USAGE);
+ }
+ check_final_program (the_program);
+
+#if O_BINARY
+ if (binary_mode)
+ {
+ if (set_binary_mode ( fileno (stdin), O_BINARY) == -1)
+ panic (_("failed to set binary mode on STDIN"));
+ if (set_binary_mode ( fileno (stdout), O_BINARY) == -1)
+ panic (_("failed to set binary mode on STDOUT"));
+ }
+#endif
+
+ if (debug)
+ debug_print_program (the_program);
+
+ return_code = process_files (the_program, argv+optind);
+
+ finish_program (the_program);
+ ck_fclose (NULL);
+
+ return return_code;
+}