diff options
Diffstat (limited to 'locale/programs/record-status.c')
-rw-r--r-- | locale/programs/record-status.c | 229 |
1 files changed, 229 insertions, 0 deletions
diff --git a/locale/programs/record-status.c b/locale/programs/record-status.c new file mode 100644 index 0000000000..730679a795 --- /dev/null +++ b/locale/programs/record-status.c @@ -0,0 +1,229 @@ +/* Functions for recorded errors, warnings, and verbose messages. + Copyright (C) 1998-2018 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/>. */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <stdbool.h> +#include <string.h> +#include <error.h> +#include <errno.h> +#include <locale.h> + +#include "record-status.h" + +/* Warnings recorded by record_warnings. */ +int recorded_warning_count; + +/* Errors recorded by record_errors. */ +int recorded_error_count; + +/* If not zero suppress warnings and information messages. */ +int be_quiet; + +/* If not zero give a lot more messages. */ +int verbose; + +/* Warnings which can be disabled: */ +/* By default we check the character map for ASCII compatibility. */ +bool warn_ascii = true; +/* By default we check that the international currency symbol matches a + known country code. */ +bool warn_int_curr_symbol = true; + +/* Alter the current locale to match the locale configured by the + user, and return the previous saved state. */ +struct locale_state +push_locale (void) +{ + int saved_errno; + const char *orig; + char *copy = NULL; + + saved_errno = errno; + + orig = setlocale (LC_CTYPE, NULL); + if (orig == NULL) + error (0, 0, "failed to read locale!"); + + if (setlocale (LC_CTYPE, "") == NULL) + error (0, 0, "failed to set locale!"); + + errno = saved_errno; + + if (orig != NULL) + copy = strdup (orig); + + /* We will return either a valid locale or NULL if we failed + to save the locale. */ + return (struct locale_state) { .cur_locale = copy }; +} + +/* Use the saved state to restore the locale. */ +void +pop_locale (struct locale_state ls) +{ + const char *set = NULL; + /* We might have failed to save the locale, so only attempt to + restore a validly saved non-NULL locale. */ + if (ls.cur_locale != NULL) + { + set = setlocale (LC_CTYPE, ls.cur_locale); + if (set == NULL) + error (0, 0, "failed to restore %s locale!", ls.cur_locale); + + free (ls.cur_locale); + } +} + +/* Wrapper to print verbose informative messages. + Verbose messages are only printed if --verbose + is in effect and --quiet is not. */ +void +__attribute__ ((__format__ (__printf__, 2, 3), nonnull (1, 2), unused)) +record_verbose (FILE *stream, const char *format, ...) +{ + char *str; + va_list arg; + + if (!verbose) + return; + + if (!be_quiet) + { + struct locale_state ls; + int ret; + + va_start (arg, format); + ls = push_locale (); + + ret = vasprintf (&str, format, arg); + if (ret == -1) + abort (); + + pop_locale (ls); + va_end (arg); + + fprintf (stream, "[verbose] %s\n", str); + + free (str); + } +} + +/* Wrapper to print warning messages. We keep track of how + many were called because this effects our exit code. + Nothing is printed if --quiet is in effect, but warnings + are always counted. */ +void +__attribute__ ((__format__ (__printf__, 1, 2), nonnull (1), unused)) +record_warning (const char *format, ...) +{ + char *str; + va_list arg; + + recorded_warning_count++; + + if (!be_quiet) + { + struct locale_state ls; + int ret; + + va_start (arg, format); + ls = push_locale (); + + ret = vasprintf (&str, format, arg); + if (ret == -1) + abort (); + + pop_locale (ls); + va_end (arg); + + fprintf (stderr, "[warning] %s\n", str); + + free (str); + } +} + +/* Wrapper to print error messages. We keep track of how + many were called because this effects our exit code. + Nothing is printed if --quiet is in effect, but errors + are always counted, and fatal errors always exit the + program. */ +void +__attribute__ ((__format__ (__printf__, 3, 4), nonnull (3), unused)) +record_error (int status, int errnum, const char *format, ...) +{ + char *str; + va_list arg; + + recorded_error_count++; + + /* The existing behaviour is that even if you use --quiet, a fatal + error is always printed and terminates the process. */ + if (!be_quiet || status != 0) + { + struct locale_state ls; + int ret; + + va_start (arg, format); + ls = push_locale (); + + ret = vasprintf (&str, format, arg); + if (ret == -1) + abort (); + + pop_locale (ls); + va_end (arg); + + error (status, errnum, "[error] %s", str); + + free (str); + } +} +/* ... likewise for error_at_line. */ +void +__attribute__ ((__format__ (__printf__, 5, 6), nonnull (3, 5), unused)) +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++; + + /* The existing behaviour is that even if you use --quiet, a fatal + error is always printed and terminates the process. */ + if (!be_quiet || status != 0) + { + struct locale_state ls; + int ret; + + va_start (arg, format); + ls = push_locale (); + + ret = vasprintf (&str, format, arg); + if (ret == -1) + abort (); + + pop_locale (ls); + va_end (arg); + + error_at_line (status, errnum, filename, linenum, "[error] %s", str); + + free (str); + } +} |