This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] locale: Fix localedef exit code [BZ #22292]


This is part of my cleanup fixes to get error codes working
reliably while I work on fixing bug 21302, where codepoint
collation for points beyond <UFFFF> doesn't work.

~~~ commit msg:
locale: Fix localedef exit code (Bug 22292)

The error and warning handling in localedef, locale, and iconv
is a bit of a mess.

We use ugly constructs like this:
      WITH_CUR_LOCALE (error (1, errno, gettext ("\
cannot read character map directory `%s'"), directory));

to issue errors, and read error_message_count directly from the
error API to detect errors. The problem with that is that the
code also uses error to print warnings, and informative messages.
All of this leads to problems where just having warnings will
produce an exit status as-if errors had been seen.

To fix this situation I have adopted the following high-level
changes:
* All errors are counted distinctly.
* All warnings are counted distinctly.
* All informative messages are not counted.
* Increasing verbosity cannot generate *more* errors, and
  it previously did for errors conditional on verbose,
  this is now fixed.
* Increasing verbosity *can* generate *more* warnings.
* Making the output quiet cannot generate *less* errors,
  and it previously did for errors conditional on be_quiet,
  this is now fixed.
* Each of error, warning, and informative message has it's
  own function to call defined in record-status.h, and they
  are: record_error, record_warning, and record_verbose.
* The record_error function always records an error, but
  conditional on be_quiet may not print it.
* The record_warning function always records a warning,
  but conditional on be_quiet may not print it.
* The record_verbose function only prints the verbose
  message if verbose is true and be_quiet is false.

This has allowed the following fix:
* Previously any warnings were being treated as errors
  because they incremented error_message_count, but now
  we properly return an exit status of 1 if there are
  warnings but output was generated.

All of this allows localedef to correctly decide if errors,
or warnings were present, and produce the correct exit code.

The locale and iconv programs now also use record-status.h
and we have removed the WITH_CUR_LOCALE hack, and instead
have internal push_locale/pop_locale functions centralized
in the record routines.

Signed-off-by: Carlos O'Donell <carlos@redhat.com>
~~~

-- 
Cheers,
Carlos.
diff --git a/ChangeLog b/ChangeLog
index 6b3a98c..ccdb403 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,64 @@
 2017-10-12  Carlos O'Donell  <carlos@redhat.com>
 
+	[BZ #22292]
+	* locale/programs/record-status.h: New file
+	* iconv/iconv_prog.c: Define recorded_error_count,
+	recorded_warning_count, and be_quiet.
+	* locale/programs/charmap-dir.c: Don't include error.h.
+	(charmap_opendir): Use record_error.
+	* locale/programs/charmap.c: Don't include error.h.
+	(charmap_read): Use record_error, and record_warning.
+	(parse_charmap): Likewise.
+	* locale/programs/ld-address.c: Don't include error.h.
+	(address_finish): Use record_error, and record_warning.
+	* locale/programs/ld-collate.c: Don't include error.h.
+	(collate_finish): Use record_error, and record_error_at_line.
+	* locale/programs/ld-ctype.c (ctype_finish): Use record_error.
+	(ctype_class_new): Likewise.
+	(ctype_map_new): Likewise.
+	(set_one_default): Likewise.
+	(set_class_defaults): Likewise.
+	(translit_flatten): Likewise.
+	(allocate_arrays): Use record_error, and record_verbose.
+	* locale/programs/ld-identification.c: Don't include error.h.
+	(indentation_finish): Use record_error and record_warning.
+	* locale/programs/ld-measurement.c: Don't include error.h.
+	(measurement_finish): Use record_error.
+	* locale/programs/ld-messages.c
+	(message_finish): Likewise.
+	* locale/programs/ld-monetary.c
+	(monetary_finish): Likewise.
+	* locale/programs/ld-name.c (name_finish): Use record_error
+	and record_warning.
+	* locale/programs/ld-numeric.c
+	(numeric_finish): Use record_error.
+	* locale/programs/ld-paper.c: Don't include error.h.
+	(paper_finish): Use record_error.
+	* locale/programs/ld-telephone.c: Don't include error.h.
+	(telephone_finish): Use record_error.
+	* locale/programs/ld-time.c (time_finish): Likewise.
+	* locale/programs/linereader.h (lr_error): Make inline func.
+	* locale/programs/locale.c: Define be_quiet,
+	and recorded_error_count.
+	* locale/programs/localedef.c: Define recorded_warning_count,
+	and recorded_error_count.
+	(main): Use record_error. Use recorded_error_count and
+	recorded_warning_count to issue correct error returns.
+	(add_to_readlist): Use record_error.
+	(find_locale): Likewise.
+	(load_locale): Likewise.
+	* locale/programs/localedef.h: Remove be_quiet
+	and WITH_CUR_LOCALE.
+	* locale/programs/locarchive.c (compare_from_file): Use
+	record_error.
+	* locale/programs/locfile.c (write_locale_data): Use
+	record_error.
+	* locale/programs/repertoire.c: Dont include error.h.
+	(repertoire_complain): Use record_error.
+
+
+2017-10-12  Carlos O'Donell  <carlos@redhat.com>
+
 	* localedata/unicode-gen/Makefile (GENERATED): Use i18n_ctype.
 	(REPORTS): Likewise.
 	(check): Likewise.
diff --git a/iconv/iconv_prog.c b/iconv/iconv_prog.c
index 35d6eb3..defaa5d 100644
--- a/iconv/iconv_prog.c
+++ b/iconv/iconv_prog.c
@@ -100,6 +100,13 @@ static const char *output_file;
 /* Nonzero if verbose ouput is wanted.  */
 int verbose;
 
+/* Number of errors seen.  */
+int recorded_error_count;
+/* Number of warnings seen.  */
+int recorded_warning_count;
+/* By default all warnings and errors are printed.  */
+int be_quiet;
+
 /* Nonzero if list of all coded character sets is wanted.  */
 static int list;
 
diff --git a/locale/programs/charmap-dir.c b/locale/programs/charmap-dir.c
index e55ab86..a9212b7 100644
--- a/locale/programs/charmap-dir.c
+++ b/locale/programs/charmap-dir.c
@@ -16,7 +16,6 @@
 
 #include <dirent.h>
 #include <errno.h>
-#include <error.h>
 #include <fcntl.h>
 #include <libintl.h>
 #include <spawn.h>
@@ -54,8 +53,9 @@ charmap_opendir (const char *directory)
   dir = opendir (directory);
   if (dir == NULL)
     {
-      WITH_CUR_LOCALE (error (1, errno, gettext ("\
-cannot read character map directory `%s'"), directory));
+      record_error (1, errno, gettext ("\
+cannot read character map directory `%s'"),
+		    directory);
       return NULL;
     }
 
diff --git a/locale/programs/charmap.c b/locale/programs/charmap.c
index 129aeff..2a1428c 100644
--- a/locale/programs/charmap.c
+++ b/locale/programs/charmap.c
@@ -26,7 +26,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <error.h>
 #include <stdint.h>
 
 #include "localedef.h"
@@ -135,8 +134,9 @@ charmap_read (const char *filename, int verbose, int error_not_found,
 	result = parse_charmap (cmfile, verbose, be_quiet);
 
       if (result == NULL && error_not_found)
-	WITH_CUR_LOCALE (error (0, errno, _("\
-character map file `%s' not found"), filename));
+	record_error (0, errno,
+		      _("character map file `%s' not found"),
+		      filename);
     }
 
   if (result == NULL && filename != NULL && strchr (filename, '/') == NULL)
@@ -192,8 +192,9 @@ character map file `%s' not found"), filename));
 	result = parse_charmap (cmfile, verbose, be_quiet);
 
       if (result == NULL)
-	WITH_CUR_LOCALE (error (4, errno, _("\
-default character map file `%s' not found"), DEFAULT_CHARMAP));
+	record_error (4, errno,
+		      _("default character map file `%s' not found"),
+		      DEFAULT_CHARMAP);
     }
 
   if (result != NULL && result->code_set_name == NULL)
@@ -255,9 +256,9 @@ default character map file `%s' not found"), DEFAULT_CHARMAP));
 
       if (failed)
 	{
-	  WITH_CUR_LOCALE (fprintf (stderr, _("\
+	  record_warning (0, 0, _("\
 character map `%s' is not ASCII compatible, locale not ISO C compliant\n"),
-				    result->code_set_name));
+			  result->code_set_name);
 	  enc_not_ascii_compatible = true;
 	}
     }
@@ -333,10 +334,9 @@ parse_charmap (struct linereader *cmfile, int verbose, int be_quiet)
 		result->mb_cur_min = result->mb_cur_max;
 	      if (result->mb_cur_min > result->mb_cur_max)
 		{
-		  if (!be_quiet)
-		    WITH_CUR_LOCALE (error (0, 0, _("\
+		  record_error (0, 0, _("\
 %s: <mb_cur_max> must be greater than <mb_cur_min>\n"),
-					    cmfile->fname));
+				cmfile->fname);
 
 		  result->mb_cur_min = result->mb_cur_max;
 		}
@@ -395,11 +395,10 @@ parse_charmap (struct linereader *cmfile, int verbose, int be_quiet)
 	      if (arg->tok != tok_number)
 		goto badarg;
 
-	      if (verbose
-		  && ((nowtok == tok_mb_cur_max
+	      if ((nowtok == tok_mb_cur_max
 		       && result->mb_cur_max != 0)
 		      || (nowtok == tok_mb_cur_max
-			  && result->mb_cur_max != 0)))
+			  && result->mb_cur_max != 0))
 		lr_error (cmfile, _("duplicate definition of <%s>"),
 			  nowtok == tok_mb_cur_min
 			  ? "mb_cur_min" : "mb_cur_max");
@@ -839,16 +838,16 @@ only WIDTH definitions are allowed to follow the CHARMAP definition"));
 	  continue;
 
 	default:
-	  WITH_CUR_LOCALE (error (5, 0, _("%s: error in state machine"),
-				  __FILE__));
+	  record_error (5, 0, _("%s: error in state machine"),
+			__FILE__);
 	  /* NOTREACHED */
 	}
       break;
     }
 
-  if (state != 91 && !be_quiet)
-    WITH_CUR_LOCALE (error (0, 0, _("%s: premature end of file"),
-			    cmfile->fname));
+  if (state != 91)
+    record_error (0, 0, _("%s: premature end of file"),
+		  cmfile->fname);
 
   lr_close (cmfile);
 
diff --git a/locale/programs/ld-address.c b/locale/programs/ld-address.c
index 2488a5c..dbd637c 100644
--- a/locale/programs/ld-address.c
+++ b/locale/programs/ld-address.c
@@ -20,7 +20,6 @@
 #endif
 
 #include <byteswap.h>
-#include <error.h>
 #include <langinfo.h>
 #include <string.h>
 #include <stdint.h>
@@ -132,8 +131,8 @@ address_finish (struct localedef_t *locale, const struct charmap_t *charmap)
       if (address == NULL)
 	{
 	  if (! be_quiet)
-	    WITH_CUR_LOCALE (error (0, 0, _("\
-No definition for %s category found"), "LC_ADDRESS"));
+	    record_error (0, 0, _("\
+No definition for %s category found"), "LC_ADDRESS");
 	  address_startup (NULL, locale, 0);
 	  address = locale->categories[LC_ADDRESS].address;
 	  nothing = 1;
@@ -143,8 +142,8 @@ No definition for %s category found"), "LC_ADDRESS"));
   if (address->postal_fmt == NULL)
     {
       if (! nothing)
-	WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' not defined"),
-				"LC_ADDRESS", "postal_fmt"));
+	record_error (0, 0, _("%s: field `%s' not defined"),
+		      "LC_ADDRESS", "postal_fmt");
       /* Use as the default value the value of the i18n locale.  */
       address->postal_fmt = "%a%N%f%N%d%N%b%N%s %h %e %r%N%C-%z %T%N%c%N";
     }
@@ -155,8 +154,8 @@ No definition for %s category found"), "LC_ADDRESS"));
       const char *cp = address->postal_fmt;
 
       if (*cp == '\0')
-	WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' must not be empty"),
-				"LC_ADDRESS", "postal_fmt"));
+	record_error (0, 0, _("%s: field `%s' must not be empty"),
+		      "LC_ADDRESS", "postal_fmt");
       else
 	while (*cp != '\0')
 	  {
@@ -167,9 +166,9 @@ No definition for %s category found"), "LC_ADDRESS"));
 		  ++cp;
 		if (strchr ("nafdbshNtreClzTSc%", *cp) == NULL)
 		  {
-		    WITH_CUR_LOCALE (error (0, 0, _("\
+		    record_error (0, 0, _("\
 %s: invalid escape `%%%c' sequence in field `%s'"),
-					    "LC_ADDRESS", *cp, "postal_fmt"));
+				  "LC_ADDRESS", *cp, "postal_fmt");
 		    break;
 		  }
 	      }
@@ -181,8 +180,8 @@ No definition for %s category found"), "LC_ADDRESS"));
   if (address->cat == NULL)						      \
     {									      \
       if (verbose && ! nothing)						      \
-	WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' not defined"),	      \
-				"LC_ADDRESS", #cat));  	    		      \
+	record_warning (0, 0, _("%s: field `%s' not defined"), "LC_ADDRESS",  \
+			#cat);						      \
       address->cat = "";						      \
     }
 
@@ -199,16 +198,16 @@ No definition for %s category found"), "LC_ADDRESS"));
   if (address->lang_term == NULL)
     {
       if (verbose && ! nothing)
-	WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' not defined"),
-				"LC_ADDRESS", "lang_term"));
+	record_warning (0, 0, _("%s: field `%s' not defined"),
+			"LC_ADDRESS", "lang_term");
       address->lang_term = "";
       cnt = sizeof (iso639) / sizeof (iso639[0]);
     }
   else if (address->lang_term[0] == '\0')
     {
       if (verbose)
-	WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' must not be empty"),
-				"LC_ADDRESS", "lang_term"));
+	record_warning (0, 0, _("%s: field `%s' must not be empty"),
+			"LC_ADDRESS", "lang_term");
       cnt = sizeof (iso639) / sizeof (iso639[0]);
     }
   else
@@ -218,9 +217,9 @@ No definition for %s category found"), "LC_ADDRESS"));
 	if (strcmp (address->lang_term, iso639[cnt].term) == 0)
 	  break;
       if (cnt == sizeof (iso639) / sizeof (iso639[0]))
-	WITH_CUR_LOCALE (error (0, 0, _("\
+	record_error (0, 0, _("\
 %s: terminology language code `%s' not defined"),
-				"LC_ADDRESS", address->lang_term));
+		      "LC_ADDRESS", address->lang_term);
     }
 
   if (address->lang_ab == NULL)
@@ -228,8 +227,8 @@ No definition for %s category found"), "LC_ADDRESS"));
       if ((cnt == sizeof (iso639) / sizeof (iso639[0])
 	   || iso639[cnt].ab[0] != '\0')
 	  && verbose && ! nothing)
-	WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' not defined"),
-				"LC_ADDRESS", "lang_ab"));
+	record_warning (0, 0, _("%s: field `%s' not defined"), "LC_ADDRESS",
+			"lang_ab");
       address->lang_ab = "";
     }
   else if (address->lang_ab[0] == '\0')
@@ -237,14 +236,14 @@ No definition for %s category found"), "LC_ADDRESS"));
       if ((cnt == sizeof (iso639) / sizeof (iso639[0])
 	   || iso639[cnt].ab[0] != '\0')
 	  && verbose)
-	WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' must not be empty"),
-				"LC_ADDRESS", "lang_ab"));
+	record_warning (0, 0, _("%s: field `%s' must not be empty"),
+			"LC_ADDRESS", "lang_ab");
     }
   else if (cnt < sizeof (iso639) / sizeof (iso639[0])
 	   && iso639[cnt].ab[0] == '\0')
     {
-      WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' must not be defined"),
-			      "LC_ADDRESS", "lang_ab"));
+      record_error (0, 0, _("%s: field `%s' must not be defined"),
+		    "LC_ADDRESS", "lang_ab");
 
       address->lang_ab = "";
     }
@@ -257,16 +256,16 @@ No definition for %s category found"), "LC_ADDRESS"));
 	    if (strcmp (address->lang_ab, iso639[cnt].ab) == 0)
 	      break;
 	  if (cnt == sizeof (iso639) / sizeof (iso639[0]))
-	    WITH_CUR_LOCALE (error (0, 0, _("\
+	    record_error (0, 0, _("\
 %s: language abbreviation `%s' not defined"),
-				    "LC_ADDRESS", address->lang_ab));
+			  "LC_ADDRESS", address->lang_ab);
 	}
       else
 	if (strcmp (iso639[cnt].ab, address->lang_ab) != 0
 	    && iso639[cnt].ab[0] != '\0')
-	  WITH_CUR_LOCALE (error (0, 0, _("\
+	  record_error (0, 0, _("\
 %s: `%s' value does not match `%s' value"),
-				  "LC_ADDRESS", "lang_ab", "lang_term"));
+			"LC_ADDRESS", "lang_ab", "lang_term");
     }
 
   if (address->lang_lib == NULL)
@@ -275,8 +274,8 @@ No definition for %s category found"), "LC_ADDRESS"));
   else if (address->lang_lib[0] == '\0')
     {
       if (verbose)
-	WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' must not be empty"),
-				"LC_ADDRESS", "lang_lib"));
+	record_warning (0, 0, _("%s: field `%s' must not be empty"),
+			"LC_ADDRESS", "lang_lib");
     }
   else
     {
@@ -286,22 +285,22 @@ No definition for %s category found"), "LC_ADDRESS"));
 	    if (strcmp (address->lang_lib, iso639[cnt].lib) == 0)
 	      break;
 	  if (cnt == sizeof (iso639) / sizeof (iso639[0]))
-	    WITH_CUR_LOCALE (error (0, 0, _("\
+	    record_error (0, 0, _("\
 %s: language abbreviation `%s' not defined"),
-				    "LC_ADDRESS", address->lang_lib));
+			  "LC_ADDRESS", address->lang_lib);
 	}
       else
 	if (strcmp (iso639[cnt].ab, address->lang_ab) != 0)
-	  WITH_CUR_LOCALE (error (0, 0, _("\
+	  record_error (0, 0, _("\
 %s: `%s' value does not match `%s' value"), "LC_ADDRESS", "lang_lib",
-				  helper == 1 ? "lang_term" : "lang_ab"));
+			helper == 1 ? "lang_term" : "lang_ab");
     }
 
   if (address->country_num == 0)
     {
       if (verbose && ! nothing)
-	WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' not defined"),
-				"LC_ADDRESS", "country_num"));
+	record_warning (0, 0, _("%s: field `%s' not defined"),
+			"LC_ADDRESS", "country_num");
       cnt = sizeof (iso3166) / sizeof (iso3166[0]);
     }
   else
@@ -311,36 +310,35 @@ No definition for %s category found"), "LC_ADDRESS"));
 	  break;
 
       if (cnt == sizeof (iso3166) / sizeof (iso3166[0]))
-	WITH_CUR_LOCALE (error (0, 0, _("\
+	record_error (0, 0, _("\
 %s: numeric country code `%d' not valid"),
-				"LC_ADDRESS", address->country_num));
+		      "LC_ADDRESS", address->country_num);
     }
 
   if (address->country_ab2 == NULL)
     {
       if (verbose && ! nothing)
-	WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' not defined"),
-				"LC_ADDRESS", "country_ab2"));
+	record_warning (0, 0, _("%s: field `%s' not defined"),
+			"LC_ADDRESS", "country_ab2");
       address->country_ab2 = "  ";
     }
   else if (cnt != sizeof (iso3166) / sizeof (iso3166[0])
 	   && strcmp (address->country_ab2, iso3166[cnt].ab2) != 0)
-    WITH_CUR_LOCALE (error (0, 0,
-			    _("%s: `%s' value does not match `%s' value"),
-			    "LC_ADDRESS", "country_ab2", "country_num"));
+    record_error (0, 0, _("%s: `%s' value does not match `%s' value"),
+		  "LC_ADDRESS", "country_ab2", "country_num");
 
   if (address->country_ab3 == NULL)
     {
       if (verbose && ! nothing)
-	WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' not defined"),
-				"LC_ADDRESS", "country_ab3"));
+	record_warning (0, 0, _("%s: field `%s' not defined"),
+			"LC_ADDRESS", "country_ab3");
       address->country_ab3 = "   ";
     }
   else if (cnt != sizeof (iso3166) / sizeof (iso3166[0])
 	   && strcmp (address->country_ab3, iso3166[cnt].ab3) != 0)
-    WITH_CUR_LOCALE (error (0, 0, _("\
+    record_error (0, 0, _("\
 %s: `%s' value does not match `%s' value"),
-			    "LC_ADDRESS", "country_ab3", "country_num"));
+		  "LC_ADDRESS", "country_ab3", "country_num");
 }
 
 
diff --git a/locale/programs/ld-collate.c b/locale/programs/ld-collate.c
index cec848c..896ff94 100644
--- a/locale/programs/ld-collate.c
+++ b/locale/programs/ld-collate.c
@@ -20,7 +20,6 @@
 #endif
 
 #include <errno.h>
-#include <error.h>
 #include <stdlib.h>
 #include <wchar.h>
 #include <stdint.h>
@@ -1561,9 +1560,8 @@ collate_finish (struct localedef_t *locale, const struct charmap_t *charmap)
   if (collate == NULL)
     {
       /* No data, no check.  */
-      if (! be_quiet)
-	WITH_CUR_LOCALE (error (0, 0, _("No definition for %s category found"),
-				"LC_COLLATE"));
+      record_error (0, 0, _("No definition for %s category found"),
+		    "LC_COLLATE");
       return;
     }
 
@@ -1579,9 +1577,9 @@ collate_finish (struct localedef_t *locale, const struct charmap_t *charmap)
 	  && ((sect->rules[i] & sort_position)
 	      != (collate->current_section->rules[i] & sort_position)))
 	{
-	  WITH_CUR_LOCALE (error (0, 0, _("\
+	  record_error (0, 0, _("\
 %s: `position' must be used for a specific level in all sections or none"),
-				  "LC_COLLATE"));
+			"LC_COLLATE");
 	  break;
 	}
 
@@ -1602,10 +1600,10 @@ collate_finish (struct localedef_t *locale, const struct charmap_t *charmap)
 		  {
 		    if (runp->weights[i].w[j]->weights == NULL)
 		      {
-			WITH_CUR_LOCALE (error_at_line (0, 0, runp->file,
-							runp->line,
-							_("symbol `%s' not defined"),
-							runp->weights[i].w[j]->name));
+			record_error_at_line (0, 0, runp->file,
+					      runp->line,
+					      _("symbol `%s' not defined"),
+					      runp->weights[i].w[j]->name);
 
 			need_undefined = 1;
 			runp->weights[i].w[j] = &collate->undefined;
@@ -1678,14 +1676,15 @@ collate_finish (struct localedef_t *locale, const struct charmap_t *charmap)
 		      /* This should not happen.  It means that we have
 			 to symbols with the same byte sequence.  It is
 			 of course an error.  */
-		      WITH_CUR_LOCALE (error_at_line (0, 0, (*eptr)->file,
-						      (*eptr)->line,
-						      _("\
+		      record_error_at_line (0, 0, (*eptr)->file,
+					    (*eptr)->line,
+					    _("\
 symbol `%s' has the same encoding as"), (*eptr)->name);
-				       error_at_line (0, 0, runp->file,
-						      runp->line,
-						      _("symbol `%s'"),
-						      runp->name));
+
+		      record_error_at_line (0, 0, runp->file,
+					    runp->line,
+					    _("symbol `%s'"),
+					    runp->name);
 		      goto dont_insert;
 		    }
 		  else if (c < 0)
@@ -1784,14 +1783,15 @@ symbol `%s' has the same encoding as"), (*eptr)->name);
 		      /* This should not happen.  It means that we have
 			 two symbols with the same byte sequence.  It is
 			 of course an error.  */
-		      WITH_CUR_LOCALE (error_at_line (0, 0, (*eptr)->file,
-						      (*eptr)->line,
-						      _("\
+		      record_error_at_line (0, 0, (*eptr)->file,
+					    (*eptr)->line,
+					    _("\
 symbol `%s' has the same encoding as"), (*eptr)->name);
-				       error_at_line (0, 0, runp->file,
-						      runp->line,
-						      _("symbol `%s'"),
-						      runp->name));
+
+		      record_error_at_line (0, 0, runp->file,
+					    runp->line,
+					    _("symbol `%s'"),
+					    runp->name);
 		      goto dont_insertwc;
 		    }
 		  else if (c < 0)
@@ -1830,7 +1830,7 @@ symbol `%s' has the same encoding as"), (*eptr)->name);
 	  /* This seems not to be enforced by recent standards.  Don't
 	     emit an error, simply append UNDEFINED at the end.  */
 	  if (0)
-	    WITH_CUR_LOCALE (error (0, 0, _("no definition of `UNDEFINED'")));
+	    record_error (0, 0, _("no definition of `UNDEFINED'"));
 
 	  /* Add UNDEFINED at the end.  */
 	  collate->undefined.mborder =
@@ -1858,8 +1858,8 @@ symbol `%s' has the same encoding as"), (*eptr)->name);
   /* Bail out if we have no sections because of earlier errors.  */
   if (sect == NULL)
     {
-      WITH_CUR_LOCALE (error (EXIT_FAILURE, 0,
-			      _("too many errors; giving up")));
+      record_error (EXIT_FAILURE, 0,
+		    _("too many errors; giving up"));
       return;
     }
 
@@ -3408,8 +3408,8 @@ error while adding equivalent collating symbol"));
 	    }
 	  else if (state == 3)
 	    {
-	      WITH_CUR_LOCALE (error (0, 0, _("\
-%s: missing `reorder-end' keyword"), "LC_COLLATE"));
+	      record_error (0, 0, _("\
+%s: missing `reorder-end' keyword"), "LC_COLLATE");
 	      state = 4;
 	    }
 	  else if (state != 2 && state != 4)
@@ -3769,11 +3769,11 @@ error while adding equivalent collating symbol"));
 		    }
 		}
 	      else if (state == 3)
-		WITH_CUR_LOCALE (error (0, 0, _("\
-%s: missing `reorder-end' keyword"), "LC_COLLATE"));
+		record_error (0, 0, _("\
+%s: missing `reorder-end' keyword"), "LC_COLLATE");
 	      else if (state == 5)
-		WITH_CUR_LOCALE (error (0, 0, _("\
-%s: missing `reorder-sections-end' keyword"), "LC_COLLATE"));
+		record_error (0, 0, _("\
+%s: missing `reorder-sections-end' keyword"), "LC_COLLATE");
 	    }
 	  arg = lr_token (ldfile, charmap, result, NULL, verbose);
 	  if (arg->tok == tok_eof)
diff --git a/locale/programs/ld-ctype.c b/locale/programs/ld-ctype.c
index df266c2..284b2a3 100644
--- a/locale/programs/ld-ctype.c
+++ b/locale/programs/ld-ctype.c
@@ -427,9 +427,8 @@ ctype_finish (struct localedef_t *locale, const struct charmap_t *charmap)
 	 empty one.  */
       if (ctype == NULL)
 	{
-	  if (! be_quiet)
-	    WITH_CUR_LOCALE (error (0, 0, _("\
-No definition for %s category found"), "LC_CTYPE"));
+	  record_error (0, 0, _("\
+No definition for %s category found"), "LC_CTYPE");
 	  ctype_startup (NULL, locale, charmap, NULL, 0);
 	  ctype = locale->categories[LC_CTYPE].ctype;
 	}
@@ -446,9 +445,8 @@ No definition for %s category found"), "LC_CTYPE"));
   ctype->codeset_name = charmap->code_set_name;
   if (ctype->codeset_name == NULL)
     {
-      if (! be_quiet)
-	WITH_CUR_LOCALE (error (0, 0, _("\
-No character set name specified in charmap")));
+      record_error (0, 0, _("\
+No character set name specified in charmap"));
       ctype->codeset_name = "//UNKNOWN//";
     }
 
@@ -475,13 +473,12 @@ No character set name specified in charmap")));
 			  {
 			    uint32_t value = ctype->charnames[cnt];
 
-			    if (!be_quiet)
-			      WITH_CUR_LOCALE (error (0, 0, _("\
+			    record_error (0, 0, _("\
 character L'\\u%0*x' in class `%s' must be in class `%s'"),
-						      value > 0xffff ? 8 : 4,
-						      value,
-						      valid_table[cls1].name,
-						      valid_table[cls2].name));
+					  value > 0xffff ? 8 : 4,
+					  value,
+					  valid_table[cls1].name,
+					  valid_table[cls2].name);
 			  }
 			break;
 
@@ -490,13 +487,12 @@ character L'\\u%0*x' in class `%s' must be in class `%s'"),
 			  {
 			    uint32_t value = ctype->charnames[cnt];
 
-			    if (!be_quiet)
-			      WITH_CUR_LOCALE (error (0, 0, _("\
+			    record_error (0, 0, _("\
 character L'\\u%0*x' in class `%s' must not be in class `%s'"),
-						      value > 0xffff ? 8 : 4,
-						      value,
-						      valid_table[cls1].name,
-						      valid_table[cls2].name));
+					  value > 0xffff ? 8 : 4,
+					  value,
+					  valid_table[cls1].name,
+					  valid_table[cls2].name);
 			  }
 			break;
 
@@ -505,8 +501,8 @@ character L'\\u%0*x' in class `%s' must not be in class `%s'"),
 			break;
 
 		      default:
-			WITH_CUR_LOCALE (error (5, 0, _("\
-internal error in %s, line %u"), __FUNCTION__, __LINE__));
+			record_error (5, 0, _("\
+internal error in %s, line %u"), __FUNCTION__, __LINE__);
 		      }
 		  }
 	}
@@ -533,12 +529,11 @@ internal error in %s, line %u"), __FUNCTION__, __LINE__));
 
 			    snprintf (buf, sizeof buf, "\\%Zo", cnt);
 
-			    if (!be_quiet)
-			      WITH_CUR_LOCALE (error (0, 0, _("\
+			    record_error (0, 0, _("\
 character '%s' in class `%s' must be in class `%s'"),
-						      buf,
-						      valid_table[cls1].name,
-						      valid_table[cls2].name));
+					  buf,
+					  valid_table[cls1].name,
+					  valid_table[cls2].name);
 			  }
 			break;
 
@@ -549,12 +544,11 @@ character '%s' in class `%s' must be in class `%s'"),
 
 			    snprintf (buf, sizeof buf, "\\%Zo", cnt);
 
-			    if (!be_quiet)
-			      WITH_CUR_LOCALE (error (0, 0, _("\
+			    record_error (0, 0, _("\
 character '%s' in class `%s' must not be in class `%s'"),
-						      buf,
-						      valid_table[cls1].name,
-						      valid_table[cls2].name));
+					  buf,
+					  valid_table[cls1].name,
+					  valid_table[cls2].name);
 			  }
 			break;
 
@@ -563,8 +557,8 @@ character '%s' in class `%s' must not be in class `%s'"),
 			break;
 
 		      default:
-			WITH_CUR_LOCALE (error (5, 0, _("\
-internal error in %s, line %u"), __FUNCTION__, __LINE__));
+			record_error (5, 0, _("\
+internal error in %s, line %u"), __FUNCTION__, __LINE__);
 		      }
 		  }
 	}
@@ -579,9 +573,8 @@ internal error in %s, line %u"), __FUNCTION__, __LINE__));
 	   (ELEM (ctype, class_collection, , space_value)
 	    & BITw (tok_blank)) == 0)))
     {
-      if (!be_quiet)
-	WITH_CUR_LOCALE (error (0, 0, _("<SP> character not in class `%s'"),
-				valid_table[cnt].name));
+      record_error (0, 0, _("<SP> character not in class `%s'"),
+		    valid_table[cnt].name);
     }
   else if (((cnt = BITPOS (tok_punct),
 	     (ELEM (ctype, class_collection, , space_value)
@@ -591,10 +584,9 @@ internal error in %s, line %u"), __FUNCTION__, __LINE__));
 		 & BITw (tok_graph))
 		!= 0)))
     {
-      if (!be_quiet)
-	WITH_CUR_LOCALE (error (0, 0, _("\
+      record_error (0, 0, _("\
 <SP> character must not be in class `%s'"),
-				valid_table[cnt].name));
+				valid_table[cnt].name);
     }
   else
     ELEM (ctype, class_collection, , space_value) |= BITw (tok_print);
@@ -606,9 +598,8 @@ internal error in %s, line %u"), __FUNCTION__, __LINE__));
     space_seq = charmap_find_value (charmap, "U00000020", 9);
   if (space_seq == NULL || space_seq->nbytes != 1)
     {
-      if (!be_quiet)
-	WITH_CUR_LOCALE (error (0, 0, _("\
-character <SP> not defined in character map")));
+      record_error (0, 0, _("\
+character <SP> not defined in character map"));
     }
   else if (((cnt = BITPOS (tok_space),
 	     (ctype->class256_collection[space_seq->bytes[0]]
@@ -617,9 +608,8 @@ character <SP> not defined in character map")));
 		(ctype->class256_collection[space_seq->bytes[0]]
 		 & BIT (tok_blank)) == 0)))
     {
-      if (!be_quiet)
-	WITH_CUR_LOCALE (error (0, 0, _("<SP> character not in class `%s'"),
-				valid_table[cnt].name));
+       record_error (0, 0, _("<SP> character not in class `%s'"),
+		     valid_table[cnt].name);
     }
   else if (((cnt = BITPOS (tok_punct),
 	     (ctype->class256_collection[space_seq->bytes[0]]
@@ -628,10 +618,9 @@ character <SP> not defined in character map")));
 		(ctype->class256_collection[space_seq->bytes[0]]
 		 & BIT (tok_graph)) != 0)))
     {
-      if (!be_quiet)
-	WITH_CUR_LOCALE (error (0, 0, _("\
+      record_error (0, 0, _("\
 <SP> character must not be in class `%s'"),
-				valid_table[cnt].name));
+		    valid_table[cnt].name);
     }
   else
     ctype->class256_collection[space_seq->bytes[0]] |= BIT (tok_print);
@@ -743,8 +732,8 @@ character <SP> not defined in character map")));
       assert (ctype->mbdigits_act == ctype->wcdigits_act);
       ctype->wcdigits_act -= ctype->mbdigits_act % 10;
       ctype->mbdigits_act -= ctype->mbdigits_act % 10;
-      WITH_CUR_LOCALE (error (0, 0, _("\
-`digit' category has not entries in groups of ten")));
+      record_error (0, 0, _("\
+`digit' category has not entries in groups of ten"));
     }
 
   /* Check the input digits.  There must be a multiple of ten available.
@@ -792,8 +781,8 @@ character <SP> not defined in character map")));
 	      if (ctype->mbdigits[cnt] == NULL)
 		{
 		  /* Hum, this ain't good.  */
-		  WITH_CUR_LOCALE (error (0, 0, _("\
-no input digits defined and none of the standard names in the charmap")));
+		  record_error (0, 0, _("\
+no input digits defined and none of the standard names in the charmap"));
 
 		  ctype->mbdigits[cnt] = obstack_alloc (&((struct charmap_t *) charmap)->mem_pool,
 							sizeof (struct charseq) + 1);
@@ -857,8 +846,8 @@ no input digits defined and none of the standard names in the charmap")));
 
 	if (!warned)
 	  {
-	    WITH_CUR_LOCALE (error (0, 0, _("\
-not all characters used in `outdigit' are available in the charmap")));
+	    record_error (0, 0, _("\
+not all characters used in `outdigit' are available in the charmap"));
 	    warned = 1;
 	  }
 
@@ -874,8 +863,8 @@ not all characters used in `outdigit' are available in the charmap")));
       {
 	if (!warned)
 	  {
-	    WITH_CUR_LOCALE (error (0, 0, _("\
-not all characters used in `outdigit' are available in the repertoire")));
+	    record_error (0, 0, _("\
+not all characters used in `outdigit' are available in the repertoire"));
 	    warned = 1;
 	  }
 
@@ -1145,9 +1134,9 @@ ctype_class_new (struct linereader *lr, struct locale_ctype_t *ctype,
 
   if (ctype->nr_charclass == MAX_NR_CHARCLASS)
     /* Exit code 2 is prescribed in P1003.2b.  */
-    WITH_CUR_LOCALE (error (2, 0, _("\
+    record_error (2, 0, _("\
 implementation limit: no more than %Zd character classes allowed"),
-			    MAX_NR_CHARCLASS));
+		  MAX_NR_CHARCLASS);
 
   ctype->classnames[ctype->nr_charclass++] = name;
 }
@@ -1177,9 +1166,9 @@ ctype_map_new (struct linereader *lr, struct locale_ctype_t *ctype,
 
   if (ctype->map_collection_nr == MAX_NR_CHARMAP)
     /* Exit code 2 is prescribed in P1003.2b.  */
-    WITH_CUR_LOCALE (error (2, 0, _("\
+    record_error (2, 0, _("\
 implementation limit: no more than %d character maps allowed"),
-			    MAX_NR_CHARMAP));
+		  MAX_NR_CHARMAP);
 
   ctype->mapnames[cnt] = name;
 
@@ -2743,11 +2732,11 @@ with character code range values one must use the absolute ellipsis `...'"));
 			    {
 			      lr_error (ldfile, _("\
 %s: duplicate `default_missing' definition"), "LC_CTYPE");
-			      WITH_CUR_LOCALE (error_at_line (0, 0,
-							      ctype->default_missing_file,
-							      ctype->default_missing_lineno,
-							      _("\
-previous definition was here")));
+			      record_error_at_line (0, 0,
+						    ctype->default_missing_file,
+						    ctype->default_missing_lineno,
+						    _("\
+previous definition was here"));
 			    }
 			  else
 			    {
@@ -2885,15 +2874,14 @@ set_one_default (struct locale_ctype_t *ctype,
         }
       if (seq == NULL)
         {
-          if (!be_quiet)
-            WITH_CUR_LOCALE (error (0, 0, _("\
+          record_error (0, 0, _("\
 %s: character `%s' not defined while needed as default value"),
-                                    "LC_CTYPE", tmp));
+			"LC_CTYPE", tmp);
         }
       else if (seq->nbytes != 1)
-        WITH_CUR_LOCALE (error (0, 0, _("\
+	record_error (0, 0, _("\
 %s: character `%s' in charmap not representable with one byte"),
-                                "LC_CTYPE", tmp));
+		      "LC_CTYPE", tmp);
       else
         ctype->class256_collection[seq->bytes[0]] |= bit;
 
@@ -2982,15 +2970,14 @@ set_class_defaults (struct locale_ctype_t *ctype,
 	seq = charmap_find_value (charmap, "U00000020", 9);
       if (seq == NULL)
 	{
-	  if (!be_quiet)
-	    WITH_CUR_LOCALE (error (0, 0, _("\
+	  record_error (0, 0, _("\
 %s: character `%s' not defined while needed as default value"),
-				    "LC_CTYPE", "<space>"));
+			"LC_CTYPE", "<space>");
 	}
       else if (seq->nbytes != 1)
-	WITH_CUR_LOCALE (error (0, 0, _("\
+	record_error (0, 0, _("\
 %s: character `%s' in charmap not representable with one byte"),
-				"LC_CTYPE", "<space>"));
+		      "LC_CTYPE", "<space>");
       else
 	ctype->class256_collection[seq->bytes[0]] |= BIT (tok_space);
 
@@ -3002,15 +2989,14 @@ set_class_defaults (struct locale_ctype_t *ctype,
 	seq = charmap_find_value (charmap, "U0000000C", 9);
       if (seq == NULL)
 	{
-	  if (!be_quiet)
-	    WITH_CUR_LOCALE (error (0, 0, _("\
+	  record_error (0, 0, _("\
 %s: character `%s' not defined while needed as default value"),
-				    "LC_CTYPE", "<form-feed>"));
+				    "LC_CTYPE", "<form-feed>");
 	}
       else if (seq->nbytes != 1)
-	WITH_CUR_LOCALE (error (0, 0, _("\
+	record_error (0, 0, _("\
 %s: character `%s' in charmap not representable with one byte"),
-				"LC_CTYPE", "<form-feed>"));
+		      "LC_CTYPE", "<form-feed>");
       else
 	ctype->class256_collection[seq->bytes[0]] |= BIT (tok_space);
 
@@ -3023,15 +3009,14 @@ set_class_defaults (struct locale_ctype_t *ctype,
 	seq = charmap_find_value (charmap, "U0000000A", 9);
       if (seq == NULL)
 	{
-	  if (!be_quiet)
-	    WITH_CUR_LOCALE (error (0, 0, _("\
+	  record_error (0, 0, _("\
 %s: character `%s' not defined while needed as default value"),
-				    "LC_CTYPE", "<newline>"));
+			"LC_CTYPE", "<newline>");
 	}
       else if (seq->nbytes != 1)
-	WITH_CUR_LOCALE (error (0, 0, _("\
+	record_error (0, 0, _("\
 %s: character `%s' in charmap not representable with one byte"),
-				"LC_CTYPE", "<newline>"));
+		      "LC_CTYPE", "<newline>");
       else
 	ctype->class256_collection[seq->bytes[0]] |= BIT (tok_space);
 
@@ -3044,15 +3029,14 @@ set_class_defaults (struct locale_ctype_t *ctype,
 	seq = charmap_find_value (charmap, "U0000000D", 9);
       if (seq == NULL)
 	{
-	  if (!be_quiet)
-	    WITH_CUR_LOCALE (error (0, 0, _("\
+	  record_error (0, 0, _("\
 %s: character `%s' not defined while needed as default value"),
-				    "LC_CTYPE", "<carriage-return>"));
+			"LC_CTYPE", "<carriage-return>");
 	}
       else if (seq->nbytes != 1)
-	WITH_CUR_LOCALE (error (0, 0, _("\
+	record_error (0, 0, _("\
 %s: character `%s' in charmap not representable with one byte"),
-				"LC_CTYPE", "<carriage-return>"));
+		      "LC_CTYPE", "<carriage-return>");
       else
 	ctype->class256_collection[seq->bytes[0]] |= BIT (tok_space);
 
@@ -3065,15 +3049,14 @@ set_class_defaults (struct locale_ctype_t *ctype,
 	seq = charmap_find_value (charmap, "U00000009", 9);
       if (seq == NULL)
 	{
-	  if (!be_quiet)
-	    WITH_CUR_LOCALE (error (0, 0, _("\
+	  record_error (0, 0, _("\
 %s: character `%s' not defined while needed as default value"),
-				    "LC_CTYPE", "<tab>"));
+			"LC_CTYPE", "<tab>");
 	}
       else if (seq->nbytes != 1)
-	WITH_CUR_LOCALE (error (0, 0, _("\
+	record_error (0, 0, _("\
 %s: character `%s' in charmap not representable with one byte"),
-				"LC_CTYPE", "<tab>"));
+		      "LC_CTYPE", "<tab>");
       else
 	ctype->class256_collection[seq->bytes[0]] |= BIT (tok_space);
 
@@ -3086,15 +3069,14 @@ set_class_defaults (struct locale_ctype_t *ctype,
 	seq = charmap_find_value (charmap, "U0000000B", 9);
       if (seq == NULL)
 	{
-	  if (!be_quiet)
-	    WITH_CUR_LOCALE (error (0, 0, _("\
+	  record_error (0, 0, _("\
 %s: character `%s' not defined while needed as default value"),
-				    "LC_CTYPE", "<vertical-tab>"));
+			"LC_CTYPE", "<vertical-tab>");
 	}
       else if (seq->nbytes != 1)
-	WITH_CUR_LOCALE (error (0, 0, _("\
+	record_error (0, 0, _("\
 %s: character `%s' in charmap not representable with one byte"),
-				"LC_CTYPE", "<vertical-tab>"));
+		      "LC_CTYPE", "<vertical-tab>");
       else
 	ctype->class256_collection[seq->bytes[0]] |= BIT (tok_space);
 
@@ -3126,15 +3108,14 @@ set_class_defaults (struct locale_ctype_t *ctype,
 	seq = charmap_find_value (charmap, "U00000020", 9);
       if (seq == NULL)
 	{
-	  if (!be_quiet)
-	    WITH_CUR_LOCALE (error (0, 0, _("\
+	  record_error (0, 0, _("\
 %s: character `%s' not defined while needed as default value"),
-				    "LC_CTYPE", "<space>"));
+			"LC_CTYPE", "<space>");
 	}
       else if (seq->nbytes != 1)
-	WITH_CUR_LOCALE (error (0, 0, _("\
+	record_error (0, 0, _("\
 %s: character `%s' in charmap not representable with one byte"),
-				"LC_CTYPE", "<space>"));
+		      "LC_CTYPE", "<space>");
       else
 	ctype->class256_collection[seq->bytes[0]] |= BIT (tok_blank);
 
@@ -3147,15 +3128,14 @@ set_class_defaults (struct locale_ctype_t *ctype,
 	seq = charmap_find_value (charmap, "U00000009", 9);
       if (seq == NULL)
 	{
-	  if (!be_quiet)
-	    WITH_CUR_LOCALE (error (0, 0, _("\
+	   record_error (0, 0, _("\
 %s: character `%s' not defined while needed as default value"),
-				    "LC_CTYPE", "<tab>"));
+		         "LC_CTYPE", "<tab>");
 	}
       else if (seq->nbytes != 1)
-	WITH_CUR_LOCALE (error (0, 0, _("\
+	record_error (0, 0, _("\
 %s: character `%s' in charmap not representable with one byte"),
-				"LC_CTYPE", "<tab>"));
+		      "LC_CTYPE", "<tab>");
       else
 	ctype->class256_collection[seq->bytes[0]] |= BIT (tok_blank);
 
@@ -3212,15 +3192,14 @@ set_class_defaults (struct locale_ctype_t *ctype,
 	seq = charmap_find_value (charmap, "U00000020", 9);
       if (seq == NULL)
 	{
-	  if (!be_quiet)
-	    WITH_CUR_LOCALE (error (0, 0, _("\
+	  record_error (0, 0, _("\
 %s: character `%s' not defined while needed as default value"),
-				    "LC_CTYPE", "<space>"));
+			"LC_CTYPE", "<space>");
 	}
       else if (seq->nbytes != 1)
-	WITH_CUR_LOCALE (error (0, 0, _("\
+	record_error (0, 0, _("\
 %s: character `%s' in charmap not representable with one byte"),
-				"LC_CTYPE", "<space>"));
+		      "LC_CTYPE", "<space>");
       else
 	ctype->class256_collection[seq->bytes[0]] |= BIT (tok_print);
 
@@ -3254,17 +3233,15 @@ set_class_defaults (struct locale_ctype_t *ctype,
 	    }
 	  if (seq_from == NULL)
 	    {
-	      if (!be_quiet)
-		WITH_CUR_LOCALE (error (0, 0, _("\
+	      record_error (0, 0, _("\
 %s: character `%s' not defined while needed as default value"),
-					"LC_CTYPE", tmp));
+			    "LC_CTYPE", tmp);
 	    }
 	  else if (seq_from->nbytes != 1)
 	    {
-	      if (!be_quiet)
-		WITH_CUR_LOCALE (error (0, 0, _("\
+	      record_error (0, 0, _("\
 %s: character `%s' needed as default value not representable with one byte"),
-					"LC_CTYPE", tmp));
+			    "LC_CTYPE", tmp);
 	    }
 	  else
 	    {
@@ -3279,17 +3256,15 @@ set_class_defaults (struct locale_ctype_t *ctype,
 		}
 	      if (seq_to == NULL)
 		{
-		  if (!be_quiet)
-		    WITH_CUR_LOCALE (error (0, 0, _("\
+		  record_error (0, 0, _("\
 %s: character `%s' not defined while needed as default value"),
-					    "LC_CTYPE", tmp));
+				"LC_CTYPE", tmp);
 		}
 	      else if (seq_to->nbytes != 1)
 		{
-		  if (!be_quiet)
-		    WITH_CUR_LOCALE (error (0, 0, _("\
+		  record_error (0, 0, _("\
 %s: character `%s' needed as default value not representable with one byte"),
-					    "LC_CTYPE", tmp));
+				"LC_CTYPE", tmp);
 		}
 	      else
 		/* The index [0] is determined by the order of the
@@ -3321,9 +3296,9 @@ set_class_defaults (struct locale_ctype_t *ctype,
   if (ctype->outdigits_act != 10)
     {
       if (ctype->outdigits_act != 0)
-	WITH_CUR_LOCALE (error (0, 0, _("\
+	record_error (0, 0, _("\
 %s: field `%s' does not contain exactly ten entries"),
-				"LC_CTYPE", "outdigit"));
+		      "LC_CTYPE", "outdigit");
 
       for (size_t cnt = ctype->outdigits_act; cnt < 10; ++cnt)
 	{
@@ -3343,8 +3318,8 @@ set_class_defaults (struct locale_ctype_t *ctype,
 	  if (ctype->mboutdigits[cnt] == NULL)
 	    {
 	      /* Provide a replacement.  */
-	      WITH_CUR_LOCALE (error (0, 0, _("\
-no output digits defined and none of the standard names in the charmap")));
+	      record_error (0, 0, _("\
+no output digits defined and none of the standard names in the charmap"));
 
 	      ctype->mboutdigits[cnt] = obstack_alloc (&((struct charmap_t *) charmap)->mem_pool,
 						       sizeof (struct charseq)
@@ -3592,9 +3567,9 @@ translit_flatten (struct locale_ctype_t *ctype,
 
       if (other == NULL || other->categories[LC_CTYPE].ctype == NULL)
 	{
-	  WITH_CUR_LOCALE (error (0, 0, _("\
+	  record_error (0, 0, _("\
 %s: transliteration data from locale `%s' not available"),
-				  "LC_CTYPE", copy_locale));
+			"LC_CTYPE", copy_locale);
 	}
       else
 	{
@@ -3691,11 +3666,10 @@ allocate_arrays (struct locale_ctype_t *ctype, const struct charmap_t *charmap,
 	if (ctype->class_collection[idx] & _ISwbit (nr))
 	  wctype_table_add (t, ctype->charnames[idx]);
 
-      if (verbose)
-	WITH_CUR_LOCALE (fprintf (stderr, _("\
+      record_verbose (stderr, _("\
 %s: table for class \"%s\": %lu bytes\n"),
-				 "LC_CTYPE", ctype->classnames[nr],
-				 (unsigned long int) t->result_size));
+		      "LC_CTYPE", ctype->classnames[nr],
+		      (unsigned long int) t->result_size);
     }
 
   /* Room for table of mappings.  */
@@ -3756,11 +3730,10 @@ allocate_arrays (struct locale_ctype_t *ctype, const struct charmap_t *charmap,
 	  wctrans_table_add (t, ctype->charnames[idx],
 			     ctype->map_collection[nr][idx]);
 
-      if (verbose)
-	WITH_CUR_LOCALE (fprintf (stderr, _("\
+      record_verbose (stderr, _("\
 %s: table for map \"%s\": %lu bytes\n"),
-				 "LC_CTYPE", ctype->mapnames[nr],
-				 (unsigned long int) t->result_size));
+		      "LC_CTYPE", ctype->mapnames[nr],
+		      (unsigned long int) t->result_size);
     }
 
   /* Extra array for class and map names.  */
@@ -3881,9 +3854,8 @@ allocate_arrays (struct locale_ctype_t *ctype, const struct charmap_t *charmap,
     /* Set the width of L'\0' to 0.  */
     wcwidth_table_add (t, 0, 0);
 
-    if (verbose)
-      WITH_CUR_LOCALE (fprintf (stderr, _("%s: table for width: %lu bytes\n"),
-			       "LC_CTYPE", (unsigned long int) t->result_size));
+    record_verbose (stderr, _("%s: table for width: %lu bytes\n"),
+		    "LC_CTYPE", (unsigned long int) t->result_size);
   }
 
   /* Set MB_CUR_MAX.  */
diff --git a/locale/programs/ld-identification.c b/locale/programs/ld-identification.c
index 3e3ea64..581cb2b 100644
--- a/locale/programs/ld-identification.c
+++ b/locale/programs/ld-identification.c
@@ -19,7 +19,6 @@
 # include <config.h>
 #endif
 
-#include <error.h>
 #include <langinfo.h>
 #include <stdlib.h>
 #include <string.h>
@@ -129,9 +128,8 @@ identification_finish (struct localedef_t *locale,
 	 empty one.  */
       if (identification == NULL)
 	{
-	  if (! be_quiet)
-	    WITH_CUR_LOCALE (error (0, 0, _("\
-No definition for %s category found"), "LC_IDENTIFICATION"));
+	  record_error (0, 0, _("\
+No definition for %s category found"), "LC_IDENTIFICATION");
 	  identification_startup (NULL, locale, 0);
 	  identification
 	    = locale->categories[LC_IDENTIFICATION].identification;
@@ -143,8 +141,8 @@ No definition for %s category found"), "LC_IDENTIFICATION"));
   if (identification->cat == NULL)					      \
     {									      \
       if (verbose && ! nothing)						      \
-	WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' not defined"),	      \
-				"LC_IDENTIFICATION", #cat));		      \
+	record_warning (0, 0, _("%s: field `%s' not defined"),		      \
+			"LC_IDENTIFICATION", #cat);			      \
       identification->cat = "";						      \
     }
 
@@ -172,9 +170,9 @@ No definition for %s category found"), "LC_IDENTIFICATION"));
       if (identification->category[num] == NULL)
 	{
 	  if (verbose && ! nothing)
-	    WITH_CUR_LOCALE (error (0, 0, _("\
-%s: no identification for category `%s'"),
-				    "LC_IDENTIFICATION", category_name[num]));
+	    record_warning (0, 0, _("\
+%s: no identification for category `%s'"), "LC_IDENTIFICATION",
+			    category_name[num]);
 	  identification->category[num] = "";
 	}
       else
@@ -196,11 +194,11 @@ No definition for %s category found"), "LC_IDENTIFICATION"));
 	      matched = true;
 
 	  if (matched != true)
-	    WITH_CUR_LOCALE (error (0, 0, _("\
+	    record_error (0, 0, _("\
 %s: unknown standard `%s' for category `%s'"),
-				    "LC_IDENTIFICATION",
-				    identification->category[num],
-				    category_name[num]));
+			  "LC_IDENTIFICATION",
+			  identification->category[num],
+			  category_name[num]);
 	}
     }
 }
diff --git a/locale/programs/ld-measurement.c b/locale/programs/ld-measurement.c
index 92c849e..7057739 100644
--- a/locale/programs/ld-measurement.c
+++ b/locale/programs/ld-measurement.c
@@ -19,7 +19,6 @@
 # include <config.h>
 #endif
 
-#include <error.h>
 #include <langinfo.h>
 #include <string.h>
 #include <stdint.h>
@@ -90,9 +89,8 @@ measurement_finish (struct localedef_t *locale,
 	 empty one.  */
       if (measurement == NULL)
 	{
-	  if (! be_quiet)
-	    WITH_CUR_LOCALE (error (0, 0, _("\
-No definition for %s category found"), "LC_MEASUREMENT"));
+	  record_error (0, 0, _("\
+No definition for %s category found"), "LC_MEASUREMENT");
 	  measurement_startup (NULL, locale, 0);
 	  measurement = locale->categories[LC_MEASUREMENT].measurement;
 	  nothing = 1;
@@ -102,16 +100,16 @@ No definition for %s category found"), "LC_MEASUREMENT"));
   if (measurement->measurement == 0)
     {
       if (! nothing)
-	WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' not defined"),
-				"LC_MEASUREMENT", "measurement"));
+	record_error (0, 0, _("%s: field `%s' not defined"),
+		      "LC_MEASUREMENT", "measurement");
       /* Use as the default value the value of the i18n locale.  */
       measurement->measurement = 1;
     }
   else
     {
       if (measurement->measurement > 3)
-	WITH_CUR_LOCALE (error (0, 0, _("%s: invalid value for field `%s'"),
-				"LC_MEASUREMENT", "measurement"));
+	record_error (0, 0, _("%s: invalid value for field `%s'"),
+		      "LC_MEASUREMENT", "measurement");
     }
 }
 
diff --git a/locale/programs/ld-messages.c b/locale/programs/ld-messages.c
index bc86ec0..e44ec57 100644
--- a/locale/programs/ld-messages.c
+++ b/locale/programs/ld-messages.c
@@ -93,9 +93,8 @@ messages_finish (struct localedef_t *locale, const struct charmap_t *charmap)
 	 empty one.  */
       if (messages == NULL)
 	{
-	  if (! be_quiet)
-	    WITH_CUR_LOCALE (error (0, 0, _("\
-No definition for %s category found"), "LC_MESSAGES"));
+	  record_error (0, 0, _("\
+No definition for %s category found"), "LC_MESSAGES");
 	  messages_startup (NULL, locale, 0);
 	  messages = locale->categories[LC_MESSAGES].messages;
 	  nothing = 1;
@@ -110,17 +109,16 @@ No definition for %s category found"), "LC_MESSAGES"));
 
   if (messages->yesexpr == NULL)
     {
-      if (! be_quiet && ! nothing)
-	WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' undefined"),
-				"LC_MESSAGES", "yesexpr"));
+      if (! nothing)
+	record_error (0, 0, _("%s: field `%s' undefined"),
+		      "LC_MESSAGES", "yesexpr");
       messages->yesexpr = "^[yY]";
     }
   else if (messages->yesexpr[0] == '\0')
     {
-      if (!be_quiet)
-	WITH_CUR_LOCALE (error (0, 0, _("\
+      record_error (0, 0, _("\
 %s: value for field `%s' must not be an empty string"),
-				"LC_MESSAGES", "yesexpr"));
+		    "LC_MESSAGES", "yesexpr");
     }
   else
     {
@@ -134,9 +132,9 @@ No definition for %s category found"), "LC_MESSAGES"));
 	  char errbuf[BUFSIZ];
 
 	  (void) regerror (result, &re, errbuf, BUFSIZ);
-	  WITH_CUR_LOCALE (error (0, 0, _("\
+	  record_error (0, 0, _("\
 %s: no correct regular expression for field `%s': %s"),
-				  "LC_MESSAGES", "yesexpr", errbuf));
+			"LC_MESSAGES", "yesexpr", errbuf);
 	}
       else if (result != 0)
 	regfree (&re);
@@ -144,17 +142,16 @@ No definition for %s category found"), "LC_MESSAGES"));
 
   if (messages->noexpr == NULL)
     {
-      if (! be_quiet && ! nothing)
-	WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' undefined"),
-				"LC_MESSAGES", "noexpr"));
+      if (! nothing)
+	record_error (0, 0, _("%s: field `%s' undefined"),
+		      "LC_MESSAGES", "noexpr");
       messages->noexpr = "^[nN]";
     }
   else if (messages->noexpr[0] == '\0')
     {
-      if (!be_quiet)
-	WITH_CUR_LOCALE (error (0, 0, _("\
+      record_error (0, 0, _("\
 %s: value for field `%s' must not be an empty string"),
-				"LC_MESSAGES", "noexpr"));
+		    "LC_MESSAGES", "noexpr");
     }
   else
     {
@@ -168,9 +165,9 @@ No definition for %s category found"), "LC_MESSAGES"));
 	  char errbuf[BUFSIZ];
 
 	  (void) regerror (result, &re, errbuf, BUFSIZ);
-	  WITH_CUR_LOCALE (error (0, 0, _("\
+	  record_error (0, 0, _("\
 %s: no correct regular expression for field `%s': %s"),
-				  "LC_MESSAGES", "noexpr", errbuf));
+			"LC_MESSAGES", "noexpr", errbuf);
 	}
       else if (result != 0)
 	regfree (&re);
diff --git a/locale/programs/ld-monetary.c b/locale/programs/ld-monetary.c
index cd50541..a0befe5 100644
--- a/locale/programs/ld-monetary.c
+++ b/locale/programs/ld-monetary.c
@@ -189,9 +189,8 @@ monetary_finish (struct localedef_t *locale, const struct charmap_t *charmap)
 	 empty one.  */
       if (monetary == NULL)
 	{
-	  if (! be_quiet)
-	    WITH_CUR_LOCALE (error (0, 0, _("\
-No definition for %s category found"), "LC_MONETARY"));
+	  record_error (0, 0, _("\
+No definition for %s category found"), "LC_MONETARY");
 	  monetary_startup (NULL, locale, 0);
 	  monetary = locale->categories[LC_MONETARY].monetary;
 	  nothing = 1;
@@ -201,9 +200,9 @@ No definition for %s category found"), "LC_MONETARY"));
 #define TEST_ELEM(cat, initval) \
   if (monetary->cat == NULL)						      \
     {									      \
-      if (! be_quiet && ! nothing)					      \
-	WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' not defined"),	      \
-				"LC_MONETARY", #cat));			      \
+      if (! nothing)							      \
+	record_error (0, 0, _("%s: field `%s' not defined"),		      \
+		      "LC_MONETARY", #cat);				      \
       monetary->cat = initval;						      \
     }
 
@@ -219,10 +218,10 @@ No definition for %s category found"), "LC_MONETARY"));
     {
       if (strlen (monetary->int_curr_symbol) != 4)
 	{
-	  if (! be_quiet && ! nothing)
-	    WITH_CUR_LOCALE (error (0, 0, _("\
+	  if (! nothing)
+	    record_error (0, 0, _("\
 %s: value of field `int_curr_symbol' has wrong length"),
-				    "LC_MONETARY"));
+			  "LC_MONETARY");
 	}
       else
 	{ /* Check the first three characters against ISO 4217 */
@@ -231,12 +230,11 @@ No definition for %s category found"), "LC_MONETARY"));
 	  symbol[3] = '\0';
 	  if (bsearch (symbol, valid_int_curr, NR_VALID_INT_CURR,
 		       sizeof (const char *),
-		       (comparison_fn_t) curr_strcmp) == NULL
-	       && !be_quiet)
-	    WITH_CUR_LOCALE (error (0, 0, _("\
+		       (comparison_fn_t) curr_strcmp) == NULL)
+	    record_error (0, 0, _("\
 %s: value of field `int_curr_symbol' does \
 not correspond to a valid name in ISO 4217"),
-				"LC_MONETARY"));
+			  "LC_MONETARY");
 	}
     }
 
@@ -245,25 +243,25 @@ not correspond to a valid name in ISO 4217"),
      != "".  */
   if (monetary->mon_decimal_point == NULL)
     {
-      if (! be_quiet && ! nothing)
-	WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' not defined"),
-				"LC_MONETARY", "mon_decimal_point"));
+      if (! nothing)
+	record_error (0, 0, _("%s: field `%s' not defined"),
+		      "LC_MONETARY", "mon_decimal_point");
       monetary->mon_decimal_point = ".";
     }
   else if (monetary->mon_decimal_point[0] == '\0' && ! be_quiet && ! nothing)
     {
-      WITH_CUR_LOCALE (error (0, 0, _("\
+      record_error (0, 0, _("\
 %s: value for field `%s' must not be an empty string"),
-			      "LC_MONETARY", "mon_decimal_point"));
+		    "LC_MONETARY", "mon_decimal_point");
     }
   if (monetary->mon_decimal_point_wc == L'\0')
     monetary->mon_decimal_point_wc = L'.';
 
   if (monetary->mon_grouping_len == 0)
     {
-      if (! be_quiet && ! nothing)
-	WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' not defined"),
-				"LC_MONETARY", "mon_grouping"));
+      if (! nothing)
+	record_error (0, 0, _("%s: field `%s' not defined"),
+		      "LC_MONETARY", "mon_grouping");
 
       monetary->mon_grouping = (char *) "\177";
       monetary->mon_grouping_len = 1;
@@ -273,17 +271,17 @@ not correspond to a valid name in ISO 4217"),
 #define TEST_ELEM(cat, min, max, initval) \
   if (monetary->cat == -2)						      \
     {									      \
-       if (! be_quiet && ! nothing)					      \
-	 WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' not defined"),	      \
-				 "LC_MONETARY", #cat));			      \
+       if (! nothing)							      \
+	 record_error (0, 0, _("%s: field `%s' not defined"),		      \
+		       "LC_MONETARY", #cat);				      \
        monetary->cat = initval;						      \
     }									      \
   else if ((monetary->cat < min || monetary->cat > max)			      \
 	   && min < max							      \
 	   && !be_quiet && !nothing)					      \
-    WITH_CUR_LOCALE (error (0, 0, _("\
+    record_error (0, 0, _("\
 %s: value for field `%s' must be in range %d...%d"),			      \
-			    "LC_MONETARY", #cat, min, max))
+		  "LC_MONETARY", #cat, min, max)
 
   TEST_ELEM (int_frac_digits, 1, 0, -1);
   TEST_ELEM (frac_digits, 1, 0, -1);
@@ -309,11 +307,10 @@ not correspond to a valid name in ISO 4217"),
 #define TEST_ELEM(cat, alt, min, max) \
   if (monetary->cat == -2)						      \
     monetary->cat = monetary->alt;					      \
-  else if ((monetary->cat < min || monetary->cat > max) && !be_quiet	      \
-	   && ! nothing)						      \
-    WITH_CUR_LOCALE (error (0, 0, _("\
+  else if ((monetary->cat < min || monetary->cat > max)	&& ! nothing)	      \
+    record_error (0, 0, _("\
 %s: value for field `%s' must be in range %d...%d"),			      \
-			    "LC_MONETARY", #cat, min, max))
+		  "LC_MONETARY", #cat, min, max)
 
   TEST_ELEM (int_p_cs_precedes, p_cs_precedes, -1, 1);
   TEST_ELEM (int_p_sep_by_space, p_sep_by_space, -1, 2);
diff --git a/locale/programs/ld-name.c b/locale/programs/ld-name.c
index ee50ae7..239595e 100644
--- a/locale/programs/ld-name.c
+++ b/locale/programs/ld-name.c
@@ -90,9 +90,8 @@ name_finish (struct localedef_t *locale, const struct charmap_t *charmap)
 	 empty one.  */
       if (name == NULL)
 	{
-	  if (! be_quiet)
-	    WITH_CUR_LOCALE (error (0, 0, _("\
-No definition for %s category found"), "LC_NAME"));
+	  record_error (0, 0, _("\
+No definition for %s category found"), "LC_NAME");
 	  name_startup (NULL, locale, 0);
 	  name = locale->categories[LC_NAME].name;
 	  nothing = 1;
@@ -102,8 +101,8 @@ No definition for %s category found"), "LC_NAME"));
   if (name->name_fmt == NULL)
     {
       if (! nothing)
-	WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' not defined"),
-				"LC_NAME", "name_fmt"));
+	record_error (0, 0, _("%s: field `%s' not defined"),
+		      "LC_NAME", "name_fmt");
       /* Use as the default value the value of the i18n locale.  */
       name->name_fmt = "%p%t%g%t%m%t%f";
     }
@@ -114,8 +113,8 @@ No definition for %s category found"), "LC_NAME"));
       const char *cp = name->name_fmt;
 
       if (*cp == '\0')
-	WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' must not be empty"),
-				"LC_NAME", "name_fmt"));
+	record_error (0, 0, _("%s: field `%s' must not be empty"),
+		      "LC_NAME", "name_fmt");
       else
 	while (*cp != '\0')
 	  {
@@ -126,8 +125,8 @@ No definition for %s category found"), "LC_NAME"));
 		  ++cp;
 		if (strchr ("dfFgGlomMpsSt", *cp) == NULL)
 		  {
-		    WITH_CUR_LOCALE (error (0, 0, _("\
-%s: invalid escape sequence in field `%s'"), "LC_NAME", "name_fmt"));
+		    record_error (0, 0, _("\
+%s: invalid escape sequence in field `%s'"), "LC_NAME", "name_fmt");
 		    break;
 		  }
 	      }
@@ -139,8 +138,8 @@ No definition for %s category found"), "LC_NAME"));
   if (name->cat == NULL)						      \
     {									      \
       if (verbose && ! nothing)						      \
-	WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' not defined"),	      \
-				"LC_NAME", #cat));          		      \
+	record_warning (0, 0, _("%s: field `%s' not defined"), "LC_NAME",     \
+			#cat);						      \
       name->cat = "";							      \
     }
 
diff --git a/locale/programs/ld-numeric.c b/locale/programs/ld-numeric.c
index a81ff04..8c04ed7 100644
--- a/locale/programs/ld-numeric.c
+++ b/locale/programs/ld-numeric.c
@@ -94,9 +94,8 @@ numeric_finish (struct localedef_t *locale, const struct charmap_t *charmap)
 	 empty one.  */
       if (numeric == NULL)
 	{
-	  if (! be_quiet)
-	    WITH_CUR_LOCALE (error (0, 0, _("\
-No definition for %s category found"), "LC_NUMERIC"));
+	  record_error (0, 0, _("\
+No definition for %s category found"), "LC_NUMERIC");
 	  numeric_startup (NULL, locale, 0);
 	  numeric = locale->categories[LC_NUMERIC].numeric;
 	  nothing = 1;
@@ -108,23 +107,23 @@ No definition for %s category found"), "LC_NUMERIC"));
      != "".  */
   if (numeric->decimal_point == NULL)
     {
-      if (! be_quiet && ! nothing)
-	WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' not defined"),
-				"LC_NUMERIC", "decimal_point"));
+      if (! nothing)
+	record_error (0, 0, _("%s: field `%s' not defined"),
+		      "LC_NUMERIC", "decimal_point");
       numeric->decimal_point = ".";
     }
-  else if (numeric->decimal_point[0] == '\0' && ! be_quiet && ! nothing)
+  else if (numeric->decimal_point[0] == '\0' && ! nothing)
     {
-      WITH_CUR_LOCALE (error (0, 0, _("\
+      record_error (0, 0, _("\
 %s: value for field `%s' must not be an empty string"),
-			      "LC_NUMERIC", "decimal_point"));
+		    "LC_NUMERIC", "decimal_point");
     }
   if (numeric->decimal_point_wc == L'\0')
     numeric->decimal_point_wc = L'.';
 
-  if (numeric->grouping_len == 0 && ! be_quiet && ! nothing)
-    WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' not defined"),
-			    "LC_NUMERIC", "grouping"));
+  if (numeric->grouping_len == 0 && ! nothing)
+    record_error (0, 0, _("%s: field `%s' not defined"),
+		  "LC_NUMERIC", "grouping");
 }
 
 
diff --git a/locale/programs/ld-paper.c b/locale/programs/ld-paper.c
index df7ce12..7bde11e 100644
--- a/locale/programs/ld-paper.c
+++ b/locale/programs/ld-paper.c
@@ -19,7 +19,6 @@
 # include <config.h>
 #endif
 
-#include <error.h>
 #include <langinfo.h>
 #include <string.h>
 #include <stdint.h>
@@ -87,9 +86,8 @@ paper_finish (struct localedef_t *locale, const struct charmap_t *charmap)
 	 empty one.  */
       if (paper == NULL)
 	{
-	  if (! be_quiet)
-	    WITH_CUR_LOCALE (error (0, 0, _("\
-No definition for %s category found"), "LC_PAPER"));
+	  record_error (0, 0, _("\
+No definition for %s category found"), "LC_PAPER");
 	  paper_startup (NULL, locale, 0);
 	  paper = locale->categories[LC_PAPER].paper;
 	  nothing = 1;
@@ -99,8 +97,8 @@ No definition for %s category found"), "LC_PAPER"));
   if (paper->height == 0)
     {
       if (! nothing)
-	WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' not defined"),
-				"LC_PAPER", "height"));
+	record_error (0, 0, _("%s: field `%s' not defined"),
+		      "LC_PAPER", "height");
       /* Use as default values the values from the i18n locale.  */
       paper->height = 297;
     }
@@ -108,8 +106,8 @@ No definition for %s category found"), "LC_PAPER"));
   if (paper->width == 0)
     {
       if (! nothing)
-	WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' not defined"),
-				"LC_PAPER", "width"));
+	record_error (0, 0, _("%s: field `%s' not defined"),
+		      "LC_PAPER", "width");
       /* Use as default values the values from the i18n locale.  */
       paper->width = 210;
     }
diff --git a/locale/programs/ld-telephone.c b/locale/programs/ld-telephone.c
index b62280a..881e7d1 100644
--- a/locale/programs/ld-telephone.c
+++ b/locale/programs/ld-telephone.c
@@ -19,7 +19,6 @@
 # include <config.h>
 #endif
 
-#include <error.h>
 #include <langinfo.h>
 #include <string.h>
 #include <stdint.h>
@@ -90,9 +89,8 @@ telephone_finish (struct localedef_t *locale, const struct charmap_t *charmap)
 	 empty one.  */
       if (telephone == NULL)
 	{
-	  if (! be_quiet)
-	    WITH_CUR_LOCALE (error (0, 0, _("\
-No definition for %s category found"), "LC_TELEPHONE"));
+	  record_error (0, 0, _("\
+No definition for %s category found"), "LC_TELEPHONE");
 	  telephone_startup (NULL, locale, 0);
 	  telephone = locale->categories[LC_TELEPHONE].telephone;
 	  nothing = 1;
@@ -102,8 +100,8 @@ No definition for %s category found"), "LC_TELEPHONE"));
   if (telephone->tel_int_fmt == NULL)
     {
       if (! nothing)
-	WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' not defined"),
-				"LC_TELEPHONE", "tel_int_fmt"));
+	record_error (0, 0, _("%s: field `%s' not defined"),
+		      "LC_TELEPHONE", "tel_int_fmt");
       /* Use as the default value the value of the i18n locale.  */
       telephone->tel_int_fmt = "+%c %a%t%l";
     }
@@ -114,8 +112,8 @@ No definition for %s category found"), "LC_TELEPHONE"));
       const char *cp = telephone->tel_int_fmt;
 
       if (*cp == '\0')
-	WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' must not be empty"),
-				"LC_TELEPHONE", "tel_int_fmt"));
+	record_error (0, 0, _("%s: field `%s' must not be empty"),
+		      "LC_TELEPHONE", "tel_int_fmt");
       else
 	while (*cp != '\0')
 	  {
@@ -123,8 +121,8 @@ No definition for %s category found"), "LC_TELEPHONE"));
 	      {
 		if (strchr ("aAcCelt", *++cp) == NULL)
 		  {
-		    WITH_CUR_LOCALE (error (0, 0, _("\
-%s: invalid escape sequence in field `%s'"), "LC_TELEPHONE", "tel_int_fmt"));
+		    record_error (0, 0, _("\
+%s: invalid escape sequence in field `%s'"), "LC_TELEPHONE", "tel_int_fmt");
 		    break;
 		  }
 	      }
@@ -146,8 +144,8 @@ No definition for %s category found"), "LC_TELEPHONE"));
 	    {
 	      if (strchr ("aAcCelt", *++cp) == NULL)
 		{
-		  WITH_CUR_LOCALE (error (0, 0, _("\
-%s: invalid escape sequence in field `%s'"), "LC_TELEPHONE", "tel_dom_fmt"));
+		  record_error (0, 0, _("\
+%s: invalid escape sequence in field `%s'"), "LC_TELEPHONE", "tel_dom_fmt");
 		  break;
 		}
 	    }
@@ -159,8 +157,8 @@ No definition for %s category found"), "LC_TELEPHONE"));
   if (telephone->cat == NULL)						      \
     {									      \
       if (verbose && ! nothing)						      \
-	WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' not defined"),	      \
-				"LC_TELEPHONE", #cat));     		      \
+	record_warning (0, 0, _("%s: field `%s' not defined"), "LC_TELEPHONE",\
+			#cat);						      \
       telephone->cat = "";						      \
     }
 
diff --git a/locale/programs/ld-time.c b/locale/programs/ld-time.c
index 32e9c41..e60dc9e 100644
--- a/locale/programs/ld-time.c
+++ b/locale/programs/ld-time.c
@@ -155,9 +155,8 @@ time_finish (struct localedef_t *locale, const struct charmap_t *charmap)
 	 empty one.  */
       if (time == NULL)
 	{
-	  if (! be_quiet)
-	    WITH_CUR_LOCALE (error (0, 0, _("\
-No definition for %s category found"), "LC_TIME"));
+	  record_error (0, 0, _("\
+No definition for %s category found"), "LC_TIME");
 	  time_startup (NULL, locale, 0);
 	  time = locale->categories[LC_TIME].time;
 	  nothing = 1;
@@ -171,9 +170,9 @@ No definition for %s category found"), "LC_TIME"));
       const char *initval[] = { noparen val };				      \
       unsigned int i;							      \
 									      \
-      if (! be_quiet && ! nothing)					      \
-	WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' not defined"),	      \
-				"LC_TIME", #cat));          		      \
+      if (! nothing)					    		      \
+	record_error (0, 0, _("%s: field `%s' not defined"),	      	      \
+		      "LC_TIME", #cat);          			      \
 									      \
       for (i = 0; i < sizeof (initval) / sizeof (initval[0]); ++i)	      \
 	time->cat[i] = initval[i];					      \
@@ -192,9 +191,9 @@ No definition for %s category found"), "LC_TIME"));
 #define TEST_ELEM(cat, initval) \
   if (time->cat == NULL)						      \
     {									      \
-      if (! be_quiet && ! nothing)					      \
-	WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' not defined"),	      \
-				"LC_TIME", #cat));          		      \
+      if (! nothing)							      \
+	record_error (0, 0, _("%s: field `%s' not defined"),		      \
+		      "LC_TIME", #cat);          			      \
 									      \
       time->cat = initval;						      \
     }
@@ -243,10 +242,9 @@ No definition for %s category found"), "LC_TIME"));
 	  /* First character must be + or - for the direction.  */
 	  if (*str != '+' && *str != '-')
 	    {
-	      if (!be_quiet)
-		WITH_CUR_LOCALE (error (0, 0, _("\
+	      record_error (0, 0, _("\
 %s: direction flag in string %Zd in `era' field is not '+' nor '-'"),
-					"LC_TIME", idx + 1));
+			    "LC_TIME", idx + 1);
 	      /* Default arbitrarily to '+'.  */
 	      time->era_entries[idx].direction = '+';
 	    }
@@ -254,10 +252,9 @@ No definition for %s category found"), "LC_TIME"));
 	    time->era_entries[idx].direction = *str;
 	  if (*++str != ':')
 	    {
-	      if (!be_quiet)
-		WITH_CUR_LOCALE (error (0, 0, _("\
+	      record_error (0, 0, _("\
 %s: direction flag in string %Zd in `era' field is not a single character"),
-					"LC_TIME", idx + 1));
+			    "LC_TIME", idx + 1);
 	      (void) strsep (&str, ":");
 	    }
 	  else
@@ -267,18 +264,16 @@ No definition for %s category found"), "LC_TIME"));
 	  time->era_entries[idx].offset = strtol (str, &endp, 10);
 	  if (endp == str)
 	    {
-	      if (!be_quiet)
-		WITH_CUR_LOCALE (error (0, 0, _("\
+	      record_error (0, 0, _("\
 %s: invalid number for offset in string %Zd in `era' field"),
-					"LC_TIME", idx + 1));
+			    "LC_TIME", idx + 1);
 	      (void) strsep (&str, ":");
 	    }
 	  else if (*endp != ':')
 	    {
-	      if (!be_quiet)
-		WITH_CUR_LOCALE (error (0, 0, _("\
+	      record_error (0, 0, _("\
 %s: garbage at end of offset value in string %Zd in `era' field"),
-					"LC_TIME", idx + 1));
+			    "LC_TIME", idx + 1);
 	      (void) strsep (&str, ":");
 	    }
 	  else
@@ -326,19 +321,17 @@ No definition for %s category found"), "LC_TIME"));
 	      if (endp == str)
 		{
 		invalid_start_date:
-		  if (!be_quiet)
-		    WITH_CUR_LOCALE (error (0, 0, _("\
+		  record_error (0, 0, _("\
 %s: invalid starting date in string %Zd in `era' field"),
-					    "LC_TIME", idx + 1));
+				"LC_TIME", idx + 1);
 		  (void) strsep (&str, ":");
 		}
 	      else if (*endp != ':')
 		{
 		garbage_start_date:
-		  if (!be_quiet)
-		    WITH_CUR_LOCALE (error (0, 0, _("\
+		  record_error (0, 0, _("\
 %s: garbage at end of starting date in string %Zd in `era' field "),
-					    "LC_TIME", idx + 1));
+				"LC_TIME", idx + 1);
 		  (void) strsep (&str, ":");
 		}
 	      else
@@ -353,11 +346,10 @@ No definition for %s category found"), "LC_TIME"));
 			   > days_per_month[time->era_entries[idx].start_date[1]])
 		       || (time->era_entries[idx].start_date[1] == 2
 			   && time->era_entries[idx].start_date[2] == 29
-			   && !__isleap (time->era_entries[idx].start_date[0])))
-		      && !be_quiet)
-			  WITH_CUR_LOCALE (error (0, 0, _("\
+			   && !__isleap (time->era_entries[idx].start_date[0]))))
+		    record_error (0, 0, _("\
 %s: starting date is invalid in string %Zd in `era' field"),
-						  "LC_TIME", idx + 1));
+				  "LC_TIME", idx + 1);
 		}
 	    }
 
@@ -403,19 +395,17 @@ No definition for %s category found"), "LC_TIME"));
 	      if (endp == str)
 		{
 		invalid_stop_date:
-		  if (!be_quiet)
-		    WITH_CUR_LOCALE (error (0, 0, _("\
+		  record_error (0, 0, _("\
 %s: invalid stopping date in string %Zd in `era' field"),
-					    "LC_TIME", idx + 1));
+				"LC_TIME", idx + 1);
 		  (void) strsep (&str, ":");
 		}
 	      else if (*endp != ':')
 		{
 		garbage_stop_date:
-		  if (!be_quiet)
-		    WITH_CUR_LOCALE (error (0, 0, _("\
+		  record_error (0, 0, _("\
 %s: garbage at end of stopping date in string %Zd in `era' field"),
-					    "LC_TIME", idx + 1));
+				"LC_TIME", idx + 1);
 		  (void) strsep (&str, ":");
 		}
 	      else
@@ -430,19 +420,17 @@ No definition for %s category found"), "LC_TIME"));
 			   > days_per_month[time->era_entries[idx].stop_date[1]])
 		       || (time->era_entries[idx].stop_date[1] == 2
 			   && time->era_entries[idx].stop_date[2] == 29
-			   && !__isleap (time->era_entries[idx].stop_date[0])))
-		      && !be_quiet)
-			  WITH_CUR_LOCALE (error (0, 0, _("\
+			   && !__isleap (time->era_entries[idx].stop_date[0]))))
+		    record_error (0, 0, _("\
 %s: invalid stopping date in string %Zd in `era' field"),
-						  "LC_TIME", idx + 1));
+				  "LC_TIME", idx + 1);
 		}
 	    }
 
 	  if (str == NULL || *str == '\0')
 	    {
-	      if (!be_quiet)
-		WITH_CUR_LOCALE (error (0, 0, _("\
-%s: missing era name in string %Zd in `era' field"), "LC_TIME", idx + 1));
+	      record_error (0, 0, _("\
+%s: missing era name in string %Zd in `era' field"), "LC_TIME", idx + 1);
 	      time->era_entries[idx].name =
 		time->era_entries[idx].format = "";
 	    }
@@ -452,10 +440,9 @@ No definition for %s category found"), "LC_TIME"));
 
 	      if (str == NULL || *str == '\0')
 		{
-		  if (!be_quiet)
-		    WITH_CUR_LOCALE (error (0, 0, _("\
+		  record_error (0, 0, _("\
 %s: missing era format in string %Zd in `era' field"),
-					    "LC_TIME", idx + 1));
+				"LC_TIME", idx + 1);
 		  time->era_entries[idx].name =
 		    time->era_entries[idx].format = "";
 		}
@@ -498,33 +485,33 @@ No definition for %s category found"), "LC_TIME"));
     time->week_1stweek = 7;
 
   if (time->week_1stweek > time->week_ndays)
-    WITH_CUR_LOCALE (error (0, 0, _("\
+    record_error (0, 0, _("\
 %s: third operand for value of field `%s' must not be larger than %d"),
-			    "LC_TIME", "week", 7));
+		  "LC_TIME", "week", 7);
 
   if (time->first_weekday == '\0')
     /* The definition does not specify this so the default is used.  */
     time->first_weekday = 1;
   else if (time->first_weekday > time->week_ndays)
-    WITH_CUR_LOCALE (error (0, 0, _("\
+    record_error (0, 0, _("\
 %s: values for field `%s' must not be larger than %d"),
-			    "LC_TIME", "first_weekday", 7));
+		  "LC_TIME", "first_weekday", 7);
 
   if (time->first_workday == '\0')
     /* The definition does not specify this so the default is used.  */
     time->first_workday = 2;
   else if (time->first_workday > time->week_ndays)
-    WITH_CUR_LOCALE (error (0, 0, _("\
+    record_error (0, 0, _("\
 %s: values for field `%s' must not be larger than %d"),
-			    "LC_TIME", "first_workday", 7));
+		  "LC_TIME", "first_workday", 7);
 
   if (time->cal_direction == '\0')
     /* The definition does not specify this so the default is used.  */
     time->cal_direction = 1;
   else if (time->cal_direction > 3)
-    WITH_CUR_LOCALE (error (0, 0, _("\
+    record_error (0, 0, _("\
 %s: values for field `%s' must not be larger than %d"),
-			    "LC_TIME", "cal_direction", 3));
+		  "LC_TIME", "cal_direction", 3);
 
   /* XXX We don't perform any tests on the timezone value since this is
      simply useless, stupid $&$!@...  */
diff --git a/locale/programs/linereader.h b/locale/programs/linereader.h
index 3965db5..2623802 100644
--- a/locale/programs/linereader.h
+++ b/locale/programs/linereader.h
@@ -27,7 +27,7 @@
 #include "error.h"
 #include "locfile-token.h"
 #include "repertoire.h"
-
+#include "record-status.h"
 
 typedef const struct keyword_t *(*kw_hash_fct_t) (const char *, unsigned int);
 struct charset_t;
@@ -96,9 +96,20 @@ extern struct token *lr_token (struct linereader *lr,
 extern void lr_ignore_rest (struct linereader *lr, int verbose);
 
 
-#define lr_error(lr, fmt, args...) \
-  WITH_CUR_LOCALE (error_at_line (0, 0, lr->fname, lr->lineno, fmt, ## args))
-
+static inline void
+lr_error (struct linereader *lr, const char *fmt, ...)
+{
+  char *str;
+  va_list arg;
+  struct locale_state ls;
+  va_start (arg, fmt); 
+  ls = push_locale ();
+  vasprintf (&str, fmt, arg);
+  pop_locale (ls);
+  va_end (arg); 
+  error_at_line (0, 0, lr->fname, lr->lineno, str);
+  free (str);
+}
 
 
 static inline int
diff --git a/locale/programs/locale.c b/locale/programs/locale.c
index 9412900..5b8ff8c 100644
--- a/locale/programs/locale.c
+++ b/locale/programs/locale.c
@@ -62,6 +62,11 @@ static int do_charmaps = 0;
 /* Nonzero if verbose output is wanted.  */
 static int verbose;
 
+/* record-status error functions need these.
+   By defuault we are not quiet.  */
+int be_quiet;
+int recorded_error_count;
+
 /* Name and version of program.  */
 static void print_version (FILE *stream, struct argp_state *state);
 void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
diff --git a/locale/programs/localedef.c b/locale/programs/localedef.c
index 6acc134..7d76154 100644
--- a/locale/programs/localedef.c
+++ b/locale/programs/localedef.c
@@ -51,6 +51,12 @@ int posix_conformance;
 /* If not zero give a lot more messages.  */
 int verbose;
 
+/* Warnings recorded by record_warnings (see localedef.h).  */
+int recorded_warning_count;
+
+/* Errors recorded by record_error (see localedef.h).  */
+int recorded_error_count;
+
 /* If not zero suppress warnings and information messages.  */
 int be_quiet;
 
@@ -236,8 +242,8 @@ main (int argc, char *argv[])
      defines error code 3 for this situation so I think it must be
      a fatal error (see P1003.2 4.35.8).  */
   if (sysconf (_SC_2_LOCALEDEF) < 0)
-    WITH_CUR_LOCALE (error (3, 0, _("\
-FATAL: system does not define `_POSIX2_LOCALEDEF'")));
+    record_error (3, 0, _("\
+FATAL: system does not define `_POSIX2_LOCALEDEF'"));
 
   /* Process charmap file.  */
   charmap = charmap_read (charmap_file, verbose, 1, be_quiet, 1);
@@ -250,8 +256,8 @@ FATAL: system does not define `_POSIX2_LOCALEDEF'")));
 
   /* Now read the locale file.  */
   if (locfile_read (&global, charmap) != 0)
-    WITH_CUR_LOCALE (error (4, errno, _("\
-cannot open locale definition file `%s'"), input_file));
+    record_error (4, errno, _("\
+cannot open locale definition file `%s'"), input_file);
 
   /* Perhaps we saw some `copy' instructions.  */
   while (1)
@@ -266,29 +272,41 @@ cannot open locale definition file `%s'"), input_file));
 	break;
 
       if (locfile_read (runp, charmap) != 0)
-	WITH_CUR_LOCALE (error (4, errno, _("\
-cannot open locale definition file `%s'"), runp->name));
+	record_error (4, errno, _("\
+cannot open locale definition file `%s'"), runp->name);
     }
 
   /* Check the categories we processed in source form.  */
   check_all_categories (locales, charmap);
 
-  /* We are now able to write the data files.  If warning were given we
-     do it only if it is explicitly requested (--force).  */
-  if (error_message_count == 0 || force_output != 0)
+  /* What we do next depends on the number of errors and warnings we
+     have generated in processing the input files.
+
+     * No errors: Write the output file.
+
+     * Some warnings: Write the output file and exit with status 1 to
+     indicate there may be problems using the output file e.g. missing
+     data that makes it difficult to use
+
+     * Errors: We don't write the output file and we exit with status 4
+     to indicate no output files were written.
+
+     The use of -c|--force writes the output file even if errors were
+     seen.  */
+  if (recorded_error_count == 0 || force_output != 0)
     {
       if (cannot_write_why != 0)
-	WITH_CUR_LOCALE (error (4, cannot_write_why, _("\
-cannot write output files to `%s'"), output_path ? : argv[remaining]));
+	record_error (4, cannot_write_why, _("\
+cannot write output files to `%s'"), output_path ? : argv[remaining]);
       else
 	write_all_categories (locales, charmap, argv[remaining], output_path);
     }
   else
-    WITH_CUR_LOCALE (error (4, 0, _("\
-no output file produced because warnings were issued")));
+    record_error (4, 0, _("\
+no output file produced because errors were issued"));
 
   /* This exit status is prescribed by POSIX.2 4.35.7.  */
-  exit (error_message_count != 0);
+  exit (recorded_warning_count != 0);
 }
 
 
@@ -567,14 +585,14 @@ add_to_readlist (int category, const char *name, const char *repertoire_name,
   if (generate
       && (runp->needed & (1 << category)) != 0
       && (runp->avail & (1 << category)) == 0)
-    WITH_CUR_LOCALE (error (5, 0, _("\
-circular dependencies between locale definitions")));
+    record_error (5, 0, _("\
+circular dependencies between locale definitions"));
 
   if (copy_locale != NULL)
     {
       if (runp->categories[category].generic != NULL)
-	WITH_CUR_LOCALE (error (5, 0, _("\
-cannot add already read locale `%s' a second time"), name));
+	record_error (5, 0, _("\
+cannot add already read locale `%s' a second time"), name);
       else
 	runp->categories[category].generic =
 	  copy_locale->categories[category].generic;
@@ -599,8 +617,8 @@ find_locale (int category, const char *name, const char *repertoire_name,
 
   if ((result->avail & (1 << category)) == 0
       && locfile_read (result, charmap) != 0)
-    WITH_CUR_LOCALE (error (4, errno, _("\
-cannot open locale definition file `%s'"), result->name));
+    record_error (4, errno, _("\
+cannot open locale definition file `%s'"), result->name);
 
   return result;
 }
@@ -619,8 +637,8 @@ load_locale (int category, const char *name, const char *repertoire_name,
 
   if ((result->avail & (1 << category)) == 0
       && locfile_read (result, charmap) != 0)
-    WITH_CUR_LOCALE (error (4, errno, _("\
-cannot open locale definition file `%s'"), result->name));
+    record_error (4, errno, _("\
+cannot open locale definition file `%s'"), result->name);
 
   return result;
 }
diff --git a/locale/programs/localedef.h b/locale/programs/localedef.h
index 74a2eba..96aa696 100644
--- a/locale/programs/localedef.h
+++ b/locale/programs/localedef.h
@@ -24,7 +24,11 @@
 #include <locale.h>
 #include <stdbool.h>
 #include <stddef.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
 
+#include "record-status.h"
 #include "repertoire.h"
 #include "../locarchive.h"
 
@@ -111,7 +115,6 @@ struct localedef_t
 
 /* Global variables of the localedef program.  */
 extern int verbose;
-extern int be_quiet;
 extern const char *repertoire_global;
 extern int max_locarchive_open_retry;
 extern bool no_archive;
@@ -122,19 +125,6 @@ extern const char *alias_file;
 #include <programs/xmalloc.h>
 
 
-/* Wrapper to switch LC_CTYPE back to the locale specified in the
-   environment for output.  */
-#define WITH_CUR_LOCALE(stmt)					\
-  do {								\
-      int saved_errno = errno;					\
-      const char *cur_locale_ = setlocale (LC_CTYPE, NULL);	\
-      setlocale (LC_CTYPE, "");					\
-      errno = saved_errno; 					\
-      stmt;							\
-      setlocale (LC_CTYPE, cur_locale_);			\
-  } while (0)
-
-
 /* Mark given locale as to be read.  */
 extern struct localedef_t *add_to_readlist (int locale, const char *name,
 					    const char *repertoire_name,
diff --git a/locale/programs/locarchive.c b/locale/programs/locarchive.c
index f67b7b8..633c59b 100644
--- a/locale/programs/locarchive.c
+++ b/locale/programs/locarchive.c
@@ -320,8 +320,8 @@ compare_from_file (struct locarhandle *ah, void *p1, uint32_t offset2,
 {
   void *p2 = xmalloc (size);
   if (pread (ah->fd, p2, size, offset2) != size)
-    WITH_CUR_LOCALE (error (4, errno,
-			    _("cannot read data from locale archive")));
+    record_error (4, errno,
+		  _("cannot read data from locale archive"));
 
   int res = memcmp (p1, p2, size);
   free (p2);
diff --git a/locale/programs/locfile.c b/locale/programs/locfile.c
index 0990ef1..b52efcf 100644
--- a/locale/programs/locfile.c
+++ b/locale/programs/locfile.c
@@ -796,9 +796,8 @@ write_locale_data (const char *output_path, int catidx, const char *category,
 
       if (fd == -1)
 	{
-	  if (!be_quiet)
-	    WITH_CUR_LOCALE (error (0, save_err, _("\
-cannot open output file `%s' for category `%s'"), fname, category));
+	  record_error (0, save_err, _("\
+cannot open output file `%s' for category `%s'"), fname, category);
 	  free (fname);
 	  return;
 	}
@@ -820,9 +819,8 @@ cannot open output file `%s' for category `%s'"), fname, category));
 
       if (writev (fd, &vec[cnt], step) < 0)
 	{
-	  if (!be_quiet)
-	    WITH_CUR_LOCALE (error (0, errno, _("\
-failure while writing data for category `%s'"), category));
+	  record_error (0, errno, _("\
+failure while writing data for category `%s'"), category);
 	  break;
 	}
     }
@@ -916,9 +914,8 @@ failure while writing data for category `%s'"), category));
 			      unlink (fname);
 			      if (rename (tmp_fname, fname) < 0)
 				{
-				  if (!be_quiet)
-				    WITH_CUR_LOCALE (error (0, errno, _("\
-cannot create output file `%s' for category `%s'"), fname, category));
+				  record_error (0, errno, _("\
+cannot create output file `%s' for category `%s'"), fname, category);
 				}
 			      free (tmp_fname);
 			      free (other_fname);
diff --git a/locale/programs/record-status.h b/locale/programs/record-status.h
new file mode 100644
index 0000000..8701f8c
--- /dev/null
+++ b/locale/programs/record-status.h
@@ -0,0 +1,144 @@
+/* General definitions for recording error and warning status.
+   Copyright (C) 1998-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   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; version 2 of the License, 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 <http://www.gnu.org/licenses/>.  */
+#ifndef _RECORD_STATUS_H
+#define _RECORD_STATUS_H 1
+#include <stdlib.h>
+#include <stdarg.h>
+#include <error.h>
+#include <locale.h>
+
+/* The program using these functions must define these:  */
+extern int recorded_warning_count;
+extern int recorded_error_count;
+extern int be_quiet;
+extern int verbose;
+
+/* Saved state of the current locale.  */
+struct locale_state
+{
+   const char *cur_locale; 
+};
+
+/* Alter the current locale to match the locale configured by the
+   user, and return the previous saved state.  */
+static inline struct locale_state
+push_locale (void)
+{
+  int saved_errno = errno;
+  const char *cl = setlocale (LC_CTYPE, NULL);
+  setlocale (LC_CTYPE, "");
+  errno = saved_errno;
+  return (struct locale_state) { .cur_locale = cl };
+}
+
+/* Use the saved state to restore the locale.  */
+static inline void
+pop_locale (struct locale_state ls)
+{
+  setlocale (LC_CTYPE, ls.cur_locale);
+}
+
+/* Wrapper to print verbose informative messages.  */
+static inline void
+record_verbose (FILE *stream, const char *format, ...)
+{
+  char *str;
+  va_list arg;
+
+  if (!verbose)
+    return;
+
+  if (!be_quiet)
+    {
+      struct locale_state ls;
+      va_start (arg, format);
+      ls = push_locale ();
+      vasprintf (&str, format, arg);
+      pop_locale (ls);
+      va_end (arg);
+      fprintf (stream, str);
+      free (str);
+    }
+}
+
+/* Wrapper to print warning messages.  We keep track of how
+   many were called because this effects our exit code.
+   Program must provide a definition of recorded_warning_count,
+   and be_quiet.  */
+static inline void
+record_warning (int status, int errnum, const char *format, ...)
+{
+  char *str;
+  va_list arg;
+  recorded_warning_count++;
+  if (!be_quiet)
+    {
+      struct locale_state ls;
+      va_start (arg, format);
+      ls = push_locale ();
+      vasprintf (&str, format, arg);
+      pop_locale (ls);
+      va_end (arg);
+      error (status, errnum, str);
+      free (str);
+    }
+}
+
+/* Wrapper to print error messages.  We keep track of how
+   many were called because this effects our exit code.
+   Program must provide a definition of recorded_error_count
+   and be_quiet.  */
+static inline void
+record_error (int status, int errnum, const char *format, ...)
+{
+  char *str;
+  va_list arg;
+  recorded_error_count++;
+  if (!be_quiet)
+    {
+      struct locale_state ls;
+      va_start (arg, format);
+      ls = push_locale ();
+      vasprintf (&str, format, arg);
+      pop_locale (ls);
+      va_end (arg);
+      error (status, errnum, str);
+      free (str);
+    }
+}
+/* ... likewise for error_at_line.  */
+static inline void
+record_error_at_line (int status, int errnum, const char *filename,
+		      unsigned int linenum, const char *format, ...)
+{
+  char *str;
+  va_list arg;
+  recorded_error_count++;
+  if (!be_quiet)
+    {
+      struct locale_state ls;
+      va_start (arg, format);
+      ls = push_locale ();
+      vasprintf (&str, format, arg);
+      pop_locale (ls);
+      va_end (arg);
+      error_at_line (status, errnum, filename, linenum, str);
+      free (str);
+    }
+}
+
+#endif
diff --git a/locale/programs/repertoire.c b/locale/programs/repertoire.c
index 61f2c05..68f0f42 100644
--- a/locale/programs/repertoire.c
+++ b/locale/programs/repertoire.c
@@ -20,7 +20,6 @@
 #endif
 
 #include <errno.h>
-#include <error.h>
 #include <limits.h>
 #include <obstack.h>
 #include <search.h>
@@ -321,14 +320,14 @@ argument to <%s> must be a single character"),
     }
 
   if (state != 2 && state != 90 && !be_quiet)
-    WITH_CUR_LOCALE (error (0, 0, _("%s: premature end of file"),
-			    repfile->fname));
+    record_error (0, 0, _("%s: premature end of file"),
+		  repfile->fname);
 
   lr_close (repfile);
 
   if (tsearch (result, &known, &repertoire_compare) == NULL)
     /* Something went wrong.  */
-    WITH_CUR_LOCALE (error (0, errno, _("cannot save new repertoire map")));
+    record_error (0, errno, _("cannot save new repertoire map"));
 
   return result;
 }
@@ -339,8 +338,8 @@ repertoire_complain (const char *name)
 {
   if (tfind (name, &unavailable, (__compar_fn_t) strcmp) == NULL)
     {
-      WITH_CUR_LOCALE (error (0, errno, _("\
-repertoire map file `%s' not found"), name));
+      record_error (0, errno, _("\
+repertoire map file `%s' not found"), name);
 
       /* Remember that we reported this map.  */
       tsearch (name, &unavailable, (__compar_fn_t) strcmp);

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]