[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH] sed: add --error-if-unmodified to error out if input was not mut
From: |
Florian Schmaus |
Subject: |
[PATCH] sed: add --error-if-unmodified to error out if input was not mutated |
Date: |
Tue, 5 Jul 2022 11:13:27 +0200 |
Gentoo makes heavy uses of sed in its ebuilds [1]. However, there is
currently no reliable, robust nor easy way to detect if a sed call is
still required, i.e., if it still mutates the input.
Previous attempts in Gentoo to remedy the situation involved
more-or-less heavy bash machinery to detect redundant/unnecessary
invocations of sed that became no-ops [2]. In the discussions around
this, it was pointed out that the right place to fix this, is, indeed,
sed.
Hence this commit introduces the --error-if-unmodified flag, which, if
enabled, will return an exit status of 8 in case sed did not apply any
modifications to the input.
This will greatly help Gentoo with identifying stale sed invocations,
and I believe others are in the same situation and would benefit form
it too.
1: https://devmanual.gentoo.org/tools-reference/sed/
2:
https://archives.gentoo.org/gentoo-dev/message/29cdbda90ea5b8127eee73a3fd036037
---
NEWS | 2 ++
sed/execute.c | 12 +++++++++---
sed/sed.c | 13 ++++++++++++-
sed/sed.h | 3 +++
sed/utils.h | 3 ++-
5 files changed, 28 insertions(+), 5 deletions(-)
diff --git a/NEWS b/NEWS
index bdabc68de6b3..e783d371b681 100644
--- a/NEWS
+++ b/NEWS
@@ -29,6 +29,8 @@ GNU sed NEWS -*- outline
-*-
The 'r' command now accepts address 0, allowing inserting a file before
the first line.
+ New option, --error-if-unmodified flag. If enabled, sed will return
+ with an exit status of 8 if the input was not modified.
* Noteworthy changes in release 4.8 (2020-01-14) [stable]
diff --git a/sed/execute.c b/sed/execute.c
index 485bca7af523..afc33b88e644 100644
--- a/sed/execute.c
+++ b/sed/execute.c
@@ -104,6 +104,9 @@ struct input {
/* Have we done any replacements lately? This is used by the `t' command. */
static bool replaced = false;
+/* Was the input ever modified? */
+static bool modified = false;
+
/* The current output file (stdout if -i is not being used). */
static struct output output_file;
@@ -1045,7 +1048,7 @@ do_subst (struct subst *sub)
if (regs.start[0] == 0 && !sub->global)
{
/* We found a match, set the `replaced' flag. */
- replaced = true;
+ replaced = modified = true;
line.active += regs.end[0];
line.length -= regs.end[0];
@@ -1055,7 +1058,7 @@ do_subst (struct subst *sub)
else if (regs.end[0] == line.length)
{
/* We found a match, set the `replaced' flag. */
- replaced = true;
+ replaced = modified = true;
line.length = regs.start[0];
goto post_subst;
@@ -1087,7 +1090,7 @@ do_subst (struct subst *sub)
&& ++count >= sub->numb)
{
/* We found a match, set the `replaced' flag. */
- replaced = true;
+ replaced = modified = true;
/* Now expand the replacement string into the output string. */
append_replacement (&s_accum, sub->replacement, ®s);
@@ -1711,5 +1714,8 @@ process_files (struct vector *the_program, char **argv)
if (input.bad_count)
status = EXIT_BAD_INPUT;
+ if (status == EXIT_SUCCESS && error_if_unmodified && !modified)
+ status = EXIT_UNMODIFIED;
+
return status;
}
diff --git a/sed/sed.c b/sed/sed.c
index af83065f3812..fbac5a0a0c71 100644
--- a/sed/sed.c
+++ b/sed/sed.c
@@ -64,6 +64,9 @@ bool sandbox = false;
/* if set, print debugging information */
bool debug = false;
+/* if set, return an error code if the input was not mutated */
+bool error_if_unmodified = false;
+
/* How do we edit files in-place? (we don't if NULL) */
char *in_place_extension = NULL;
@@ -166,6 +169,8 @@ Usage: %s [OPTION]... {script-only-if-no-other-script}
[input-file]...\n\
continuous long stream.\n"));
fprintf (out, _(" --sandbox\n\
operate in sandbox mode (disable e/r/w commands).\n"));
+ fprintf (out, _(" --error-if-unmodified\n\
+ exit with an error code if input was not modified.\n"));
fprintf (out, _(" -u, --unbuffered\n\
load minimal amounts of data from the input files and flush\n\
the output buffers more often\n"));
@@ -191,7 +196,8 @@ main (int argc, char **argv)
#define SHORTOPTS "bsnrzuEe:f:l:i::V:"
enum { SANDBOX_OPTION = CHAR_MAX+1,
- DEBUG_OPTION
+ DEBUG_OPTION,
+ ERROR_IF_UNMODIFIED_OPTION,
};
static const struct option longopts[] = {
@@ -208,6 +214,7 @@ main (int argc, char **argv)
{"posix", 0, NULL, 'p'},
{"silent", 0, NULL, 'n'},
{"sandbox", 0, NULL, SANDBOX_OPTION},
+ {"error-if-unmodified", 0, NULL, ERROR_IF_UNMODIFIED_OPTION},
{"separate", 0, NULL, 's'},
{"unbuffered", 0, NULL, 'u'},
{"version", 0, NULL, 'v'},
@@ -332,6 +339,10 @@ main (int argc, char **argv)
debug = true;
break;
+ case ERROR_IF_UNMODIFIED_OPTION:
+ error_if_unmodified = true;
+ break;
+
case 'u':
unbuffered = true;
break;
diff --git a/sed/sed.h b/sed/sed.h
index 1c96bc56f031..aa816f1f90cc 100644
--- a/sed/sed.h
+++ b/sed/sed.h
@@ -258,6 +258,9 @@ extern bool sandbox;
/* If set, print debugging information. */
extern bool debug;
+/* if set, return an error code if the input was not mutated */
+extern bool error_if_unmodified;
+
#define MBRTOWC(pwc, s, n, ps) \
(mb_cur_max == 1 ? \
(*(pwc) = btowc (*(unsigned char *) (s)), 1) : \
diff --git a/sed/utils.h b/sed/utils.h
index cac8a057c44f..8f88b5774344 100644
--- a/sed/utils.h
+++ b/sed/utils.h
@@ -22,7 +22,8 @@ enum exit_codes {
/* EXIT_SUCCESS is already defined as 0 */
EXIT_BAD_USAGE = 1, /* bad program syntax, invalid command-line options */
EXIT_BAD_INPUT = 2, /* failed to open some of the input files */
- EXIT_PANIC = 4 /* PANIC during program execution */
+ EXIT_PANIC = 4, /* PANIC during program execution */
+ EXIT_UNMODIFIED = 8,
};
--
2.35.1