sed-devel
[Top][All Lists]
Advanced

[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, &regs);
@@ -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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]