From a65201663b73bf58a6a8f4ad6e4c8718a6748c69 Mon Sep 17 00:00:00 2001
From: Grisha Levit <grishalevit@gmail.com>
Date: Tue, 11 Jul 2023 17:18:24 -0400
Subject: [PATCH] print regerror string on regcomp error

* lib/sh/shmatch.c
- strregerror: new function, returns newly allocated string for regcomp
  error code
- sh_regmatch: accepts new argument to pass back error string. call
  strregerror on regcomp failure.
* execute_cmd.c
- execute_cond_node: pass a char* to sh_regmatch to get back regerror
  string. include string in error message.
* externs.h
- update sh_regmatch declaration
* tests/cond.right
- update for new invalid regular expression message
---
 execute_cmd.c    |  9 +++++++--
 externs.h        |  2 +-
 lib/sh/shmatch.c | 34 ++++++++++++++++++++++++----------
 tests/cond.right |  2 +-
 4 files changed, 33 insertions(+), 14 deletions(-)

diff --git a/execute_cmd.c b/execute_cmd.c
index 6bc572c7..8c86af9e 100644
--- a/execute_cmd.c
+++ b/execute_cmd.c
@@ -3975,6 +3975,8 @@ execute_cond_node (COND_COM *cond)
 #if defined (COND_REGEXP)
       if (rmatch)
 	{
+	  char *errbuf;
+
 	  mflags = SHMAT_PWARN;
 #if defined (ARRAY_VARS)
 	  mflags |= SHMAT_SUBEXP;
@@ -3988,9 +3990,12 @@ execute_cond_node (COND_COM *cond)
 	  free(t2);
 #endif
 
-	  result = sh_regmatch (arg1, arg2, mflags);
+	  result = sh_regmatch (arg1, arg2, mflags, &errbuf);
 	  if (result == 2)
-	    builtin_error (_("invalid regular expression `%s'"), arg2);
+	    {
+	      builtin_error (_("invalid regular expression `%s': %s"), arg2, errbuf);
+	      free (errbuf);
+	    }
 	}
       else
 #endif /* COND_REGEXP */
diff --git a/externs.h b/externs.h
index a1363d4d..c4a21e74 100644
--- a/externs.h
+++ b/externs.h
@@ -339,7 +339,7 @@ extern int sh_setlinebuf (FILE *);
 extern int sh_eaccess (const char *, int);
 
 /* declarations for functions defined in lib/sh/shmatch.c */
-extern int sh_regmatch (const char *, const char *, int);
+extern int sh_regmatch (const char *, const char *, int, char **);
 
 /* defines for flags argument to sh_regmatch. */
 #define SHMAT_SUBEXP		0x001	/* save subexpressions in SH_REMATCH */
diff --git a/lib/sh/shmatch.c b/lib/sh/shmatch.c
index 4262e656..0afd20a3 100644
--- a/lib/sh/shmatch.c
+++ b/lib/sh/shmatch.c
@@ -39,14 +39,27 @@
 #include "variables.h"
 #include "externs.h"
 
-extern int glob_ignore_case, match_ignore_case;
+extern int match_ignore_case;
 
 #if defined (ARRAY_VARS)
 extern SHELL_VAR *builtin_find_indexed_array (char *, int);
 #endif
 
+static char *
+strregerror (int err, const regex_t *regex_p)
+{
+  char *str;
+  size_t size;
+
+  size = regerror (err, regex_p, (char *)0, 0);
+  str = malloc (size);
+  (void)regerror (err, regex_p, str, size);
+
+  return str;
+}
+
 int
-sh_regmatch (const char *string, const char *pattern, int flags)
+sh_regmatch (const char *string, const char *pattern, int flags, char **errbuf)
 {
   regex_t regex = { 0 };
   regmatch_t *matches;
@@ -54,16 +67,13 @@ sh_regmatch (const char *string, const char *pattern, int flags)
 #if defined (ARRAY_VARS)
   SHELL_VAR *rematch;
   ARRAY *amatch;
-  int subexp_ind;
+  size_t subexp_ind;
   char *subexp_str;
-  int subexp_len;
+  size_t subexp_len;
 #endif
+  int reg_err;
   int result;
 
-#if defined (ARRAY_VARS)
-  rematch = (SHELL_VAR *)NULL;
-#endif
-
   rflags = REG_EXTENDED;
   if (match_ignore_case)
     rflags |= REG_ICASE;
@@ -71,8 +81,12 @@ sh_regmatch (const char *string, const char *pattern, int flags)
   rflags |= REG_NOSUB;
 #endif
 
-  if (regcomp (&regex, pattern, rflags))
-    return 2;		/* flag for printing a warning here. */
+  if ((reg_err = regcomp (&regex, pattern, rflags)))
+    {
+      if (errbuf)
+        *errbuf = strregerror (reg_err, &regex);
+      return 2;		/* flag for printing a warning here. */
+    }
 
 #if defined (ARRAY_VARS)
   matches = (regmatch_t *)malloc (sizeof (regmatch_t) * (regex.re_nsub + 1));
diff --git a/tests/cond.right b/tests/cond.right
index 73f61fd3..6e8fd8a3 100644
--- a/tests/cond.right
+++ b/tests/cond.right
@@ -76,7 +76,7 @@ match control-a 2
 match control-a 3
 match control-a 4
 match control-a 5
-./cond-regexp2.sub: line 18: [[: invalid regular expression `[\.'
+./cond-regexp2.sub: line 18: [[: invalid regular expression `[\.': brackets ([ ]) not balanced
 ok 1
 ok 2
 ok 3
-- 
2.41.0

