summaryrefslogtreecommitdiff
path: root/sed/sed.c
diff options
context:
space:
mode:
Diffstat (limited to 'sed/sed.c')
-rw-r--r--sed/sed.c272
1 files changed, 160 insertions, 112 deletions
diff --git a/sed/sed.c b/sed/sed.c
index af985e6..7445178 100644
--- a/sed/sed.c
+++ b/sed/sed.c
@@ -1,6 +1,5 @@
/* GNU SED, a batch stream editor.
- Copyright (C) 1989,90,91,92,93,94,95,98,99,2002,2003,2006,2008,2009,2010
- Free Software Foundation, Inc.
+ Copyright (C) 1989-2016 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
@@ -20,11 +19,15 @@
#include "sed.h"
+#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
+#include <unistd.h>
#include "getopt.h"
+#include "progname.h"
+#include "version.h"
#include "version-etc.h"
@@ -34,8 +37,6 @@
_("Ken Pizzini"), \
_("Paolo Bonzini")
-char *program_name;
-
int extended_regexp_flags = 0;
/* one-byte buffer delimiter */
@@ -53,12 +54,15 @@ 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;
+
/* 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 *read_mode = "r";
-char *write_mode = "w";
+char const *read_mode = "r";
+char const *write_mode = "w";
/* Do we need to be pedantically POSIX compliant? */
enum posixicity_types posixicity;
@@ -69,10 +73,40 @@ 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 (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(errmsg)
- int errmsg;
+contact(int errmsg)
{
FILE *out = errmsg ? stderr : stdout;
#ifndef REG_PERL
@@ -83,22 +117,18 @@ General help using GNU software: <http://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\
-Be sure to include the word ``%s'' somewhere in the ``Subject:'' field.\n"),
- PACKAGE_BUGREPORT, PACKAGE);
+ fprintf(out, _("E-mail bug reports to: <%s>.\n"), PACKAGE_BUGREPORT);
}
-static void usage (int);
-static void
-usage(status)
- int status;
+_Noreturn static void
+usage(int status)
{
FILE *out = status ? stderr : stdout;
#ifdef REG_PERL
-#define PERL_HELP _(" -R, --regexp-perl\n use Perl 5's regular expressions syntax in the script.\n")
-#else
-#define PERL_HELP ""
+#define PERL_HELP _(" -R, --regexp-perl" \
+ "\n use Perl 5's regular expressions" \
+ " syntax in the script.\n")
#endif
fprintf(out, _("\
@@ -110,29 +140,35 @@ Usage: %s [OPTION]... {script-only-if-no-other-script} [input-file]...\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"));
+ 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 defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) || defined(MSDOS) || defined(__EMX__)
+#if defined WIN32 || defined _WIN32 || defined __CYGWIN__ \
+ || defined MSDOS || defined __EMX__
fprintf(out, _(" -b, --binary\n\
- open files in binary mode (CR+LFs are not processed specially)\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, _(" -r, --regexp-extended\n\
- use extended regular expressions in the script.\n"));
+ fprintf(out, _(" -E, -r, --regexp-extended\n\
+ use extended regular expressions in the script\n\
+ (for portability use POSIX -E).\n"));
#ifdef REG_PERL
fprintf(out, PERL_HELP);
#endif
fprintf(out, _(" -s, --separate\n\
- consider files as separate rather than as a single continuous\n\
- long stream.\n"));
+ consider files as separate rather than as a single,\n\
+ continuous long stream.\n"));
+ fprintf(out, _(" --sandbox\n\
+ operate in sandbox mode.\n"));
fprintf(out, _(" -u, --unbuffered\n\
load minimal amounts of data from the input files and flush\n\
the output buffers more often\n"));
@@ -153,9 +189,7 @@ specified, then the standard input is read.\n\
}
int
-main(argc, argv)
- int argc;
- char **argv;
+main (int argc, char **argv)
{
#ifdef REG_PERL
#define SHORTOPTS "bsnrzRuEe:f:l:i::V:"
@@ -163,7 +197,9 @@ main(argc, argv)
#define SHORTOPTS "bsnrzuEe:f:l:i::V:"
#endif
- static struct option longopts[] = {
+ enum { SANDBOX_OPTION = CHAR_MAX+1 };
+
+ static const struct option longopts[] = {
{"binary", 0, NULL, 'b'},
{"regexp-extended", 0, NULL, 'r'},
#ifdef REG_PERL
@@ -178,6 +214,7 @@ main(argc, argv)
{"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'},
@@ -198,7 +235,13 @@ main(argc, argv)
/* Set locale according to user's wishes. */
setlocale (LC_ALL, "");
#endif
+ set_program_name (argv[0]);
initialize_mbcs ();
+ init_localeinfo (&localeinfo);
+
+ /* Arrange to remove any un-renamed temporary file,
+ upon premature exit. */
+ atexit (cleanup);
#if ENABLE_NLS
@@ -220,115 +263,120 @@ main(argc, argv)
{
countT t = atoi(cols);
if (t > 1)
- lcmd_out_line_len = t-1;
+ lcmd_out_line_len = t-1;
}
myname = *argv;
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 (optarg == NULL)
- /* use no backups */
- in_place_extension = ck_strdup ("*");
-
- else if (strchr(optarg, '*') != NULL)
- in_place_extension = ck_strdup(optarg);
-
- else
- {
- in_place_extension = MALLOC (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 '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 (optarg == NULL)
+ /* use no backups */
+ in_place_extension = ck_strdup ("*");
+
+ else if (strchr(optarg, '*') != NULL)
+ in_place_extension = ck_strdup(optarg);
+
+ else
+ {
+ in_place_extension = MALLOC (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";
- break;
-
- /* Undocumented, for compatibility with BSD sed. */
- case 'E':
- case 'r':
- if (extended_regexp_flags)
- usage(4);
- extended_regexp_flags = REG_EXTENDED;
- break;
+ read_mode = "rb";
+ write_mode = "wb";
+ break;
+ case 'E':
+ case 'r':
#ifdef REG_PERL
- case 'R':
- if (extended_regexp_flags)
- usage(4);
- extended_regexp_flags = REG_PERL;
- break;
+ if (extended_regexp_flags && (extended_regexp_flags!=REG_EXTENDED))
+ usage(EXIT_BAD_USAGE);
#endif
+ extended_regexp_flags = REG_EXTENDED;
+ break;
+
+#ifdef REG_PERL
+ case 'R':
+ if (extended_regexp_flags && (extended_regexp_flags!=REG_PERL)))
+ usage(EXIT_BAD_USAGE);
+ extended_regexp_flags = REG_PERL;
+ break;
+#endif
+
+ case 's':
+ separate_files = true;
+ break;
- case 's':
- separate_files = true;
- break;
+ case SANDBOX_OPTION:
+ sandbox = true;
+ break;
- case 'u':
- unbuffered = true;
- break;
+ case 'u':
+ unbuffered = true;
+ break;
- case 'v':
- version_etc(stdout, program_name, PACKAGE_NAME, VERSION,
+ case 'v':
+ version_etc(stdout, program_name, PACKAGE_NAME, Version,
AUTHORS, (char *) NULL);
- contact(false);
- ck_fclose (NULL);
- exit (0);
- case 'h':
- usage(0);
- default:
- usage(4);
- }
+ 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));
- }
+ {
+ char *arg = argv[optind++];
+ the_program = compile_string(the_program, arg, strlen(arg));
+ }
else
- usage(4);
+ usage(EXIT_BAD_USAGE);
}
check_final_program(the_program);
return_code = process_files(the_program, argv+optind);
- finish_program(the_program);
+ finish_program();
ck_fclose(NULL);
return return_code;