Blame locale/programs/record-status.c

Packit 6c4009
/* Functions for recorded errors, warnings, and verbose messages.
Packit 6c4009
   Copyright (C) 1998-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   This program is free software; you can redistribute it and/or modify
Packit 6c4009
   it under the terms of the GNU General Public License as published
Packit 6c4009
   by the Free Software Foundation; version 2 of the License, or
Packit 6c4009
   (at your option) any later version.
Packit 6c4009
Packit 6c4009
   This program is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 6c4009
   GNU General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU General Public License
Packit 6c4009
   along with this program; if not, see <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <stdarg.h>
Packit 6c4009
#include <stdbool.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <error.h>
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <locale.h>
Packit 6c4009
Packit 6c4009
#include "record-status.h"
Packit 6c4009
Packit 6c4009
/* Warnings recorded by record_warnings.  */
Packit 6c4009
int recorded_warning_count;
Packit 6c4009
Packit 6c4009
/* Errors recorded by record_errors.  */
Packit 6c4009
int recorded_error_count;
Packit 6c4009
Packit 6c4009
/* If not zero suppress warnings and information messages.  */
Packit 6c4009
int be_quiet;
Packit 6c4009
Packit 6c4009
/* If not zero give a lot more messages.  */
Packit 6c4009
int verbose;
Packit 6c4009
Packit 6c4009
/* Warnings which can be disabled:  */
Packit 6c4009
/* By default we check the character map for ASCII compatibility.  */
Packit 6c4009
bool warn_ascii = true;
Packit 6c4009
/* By default we check that the international currency symbol matches a
Packit 6c4009
   known country code.  */
Packit 6c4009
bool warn_int_curr_symbol = true;
Packit 6c4009
Packit 6c4009
/* Alter the current locale to match the locale configured by the
Packit 6c4009
   user, and return the previous saved state.  */
Packit 6c4009
struct locale_state
Packit 6c4009
push_locale (void)
Packit 6c4009
{
Packit 6c4009
  int saved_errno;
Packit 6c4009
  const char *orig;
Packit 6c4009
  char *copy = NULL;
Packit 6c4009
Packit 6c4009
  saved_errno = errno;
Packit 6c4009
Packit 6c4009
  orig = setlocale (LC_CTYPE, NULL);
Packit 6c4009
  if (orig == NULL)
Packit 6c4009
    error (0, 0, "failed to read locale!");
Packit 6c4009
Packit 6c4009
  if (setlocale (LC_CTYPE, "") == NULL)
Packit 6c4009
    error (0, 0, "failed to set locale!");
Packit 6c4009
Packit 6c4009
  errno = saved_errno;
Packit 6c4009
Packit 6c4009
  if (orig != NULL)
Packit 6c4009
    copy = strdup (orig);
Packit 6c4009
Packit 6c4009
  /* We will return either a valid locale or NULL if we failed
Packit 6c4009
     to save the locale.  */
Packit 6c4009
  return (struct locale_state) { .cur_locale = copy };
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Use the saved state to restore the locale.  */
Packit 6c4009
void
Packit 6c4009
pop_locale (struct locale_state ls)
Packit 6c4009
{
Packit 6c4009
  const char *set = NULL;
Packit 6c4009
  /* We might have failed to save the locale, so only attempt to
Packit 6c4009
     restore a validly saved non-NULL locale.  */
Packit 6c4009
  if (ls.cur_locale != NULL)
Packit 6c4009
    {
Packit 6c4009
      set = setlocale (LC_CTYPE, ls.cur_locale);
Packit 6c4009
      if (set == NULL)
Packit 6c4009
	error (0, 0, "failed to restore %s locale!", ls.cur_locale);
Packit 6c4009
Packit 6c4009
      free (ls.cur_locale);
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Wrapper to print verbose informative messages.
Packit 6c4009
   Verbose messages are only printed if --verbose
Packit 6c4009
   is in effect and --quiet is not.  */
Packit 6c4009
void
Packit 6c4009
__attribute__ ((__format__ (__printf__, 2, 3), nonnull (1, 2), unused))
Packit 6c4009
record_verbose (FILE *stream, const char *format, ...)
Packit 6c4009
{
Packit 6c4009
  char *str;
Packit 6c4009
  va_list arg;
Packit 6c4009
Packit 6c4009
  if (!verbose)
Packit 6c4009
    return;
Packit 6c4009
Packit 6c4009
  if (!be_quiet)
Packit 6c4009
    {
Packit 6c4009
      struct locale_state ls;
Packit 6c4009
      int ret;
Packit 6c4009
Packit 6c4009
      va_start (arg, format);
Packit 6c4009
      ls = push_locale ();
Packit 6c4009
Packit 6c4009
      ret = vasprintf (&str, format, arg);
Packit 6c4009
      if (ret == -1)
Packit 6c4009
	abort ();
Packit 6c4009
Packit 6c4009
      pop_locale (ls);
Packit 6c4009
      va_end (arg);
Packit 6c4009
Packit 6c4009
      fprintf (stream, "[verbose] %s\n", str);
Packit 6c4009
Packit 6c4009
      free (str);
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Wrapper to print warning messages.  We keep track of how
Packit 6c4009
   many were called because this effects our exit code.
Packit 6c4009
   Nothing is printed if --quiet is in effect, but warnings
Packit 6c4009
   are always counted.  */
Packit 6c4009
void
Packit 6c4009
__attribute__ ((__format__ (__printf__, 1, 2), nonnull (1), unused))
Packit 6c4009
record_warning (const char *format, ...)
Packit 6c4009
{
Packit 6c4009
  char *str;
Packit 6c4009
  va_list arg;
Packit 6c4009
Packit 6c4009
  recorded_warning_count++;
Packit 6c4009
Packit 6c4009
  if (!be_quiet)
Packit 6c4009
    {
Packit 6c4009
      struct locale_state ls;
Packit 6c4009
      int ret;
Packit 6c4009
Packit 6c4009
      va_start (arg, format);
Packit 6c4009
      ls = push_locale ();
Packit 6c4009
Packit 6c4009
      ret = vasprintf (&str, format, arg);
Packit 6c4009
      if (ret == -1)
Packit 6c4009
	abort ();
Packit 6c4009
Packit 6c4009
      pop_locale (ls);
Packit 6c4009
      va_end (arg);
Packit 6c4009
Packit 6c4009
      fprintf (stderr, "[warning] %s\n", str);
Packit 6c4009
Packit 6c4009
      free (str);
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Wrapper to print error messages.  We keep track of how
Packit 6c4009
   many were called because this effects our exit code.
Packit 6c4009
   Nothing is printed if --quiet is in effect, but errors
Packit 6c4009
   are always counted, and fatal errors always exit the
Packit 6c4009
   program.  */
Packit 6c4009
void
Packit 6c4009
__attribute__ ((__format__ (__printf__, 3, 4), nonnull (3), unused))
Packit 6c4009
record_error (int status, int errnum, const char *format, ...)
Packit 6c4009
{
Packit 6c4009
  char *str;
Packit 6c4009
  va_list arg;
Packit 6c4009
Packit 6c4009
  recorded_error_count++;
Packit 6c4009
Packit 6c4009
  /* The existing behaviour is that even if you use --quiet, a fatal
Packit 6c4009
     error is always printed and terminates the process.  */
Packit 6c4009
  if (!be_quiet || status != 0)
Packit 6c4009
    {
Packit 6c4009
      struct locale_state ls;
Packit 6c4009
      int ret;
Packit 6c4009
Packit 6c4009
      va_start (arg, format);
Packit 6c4009
      ls = push_locale ();
Packit 6c4009
Packit 6c4009
      ret = vasprintf (&str, format, arg);
Packit 6c4009
      if (ret == -1)
Packit 6c4009
        abort ();
Packit 6c4009
Packit 6c4009
      pop_locale (ls);
Packit 6c4009
      va_end (arg);
Packit 6c4009
Packit 6c4009
      error (status, errnum, "[error] %s", str);
Packit 6c4009
Packit 6c4009
      free (str);
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
/* ... likewise for error_at_line.  */
Packit 6c4009
void
Packit 6c4009
__attribute__ ((__format__ (__printf__, 5, 6), nonnull (3, 5), unused))
Packit 6c4009
record_error_at_line (int status, int errnum, const char *filename,
Packit 6c4009
		      unsigned int linenum, const char *format, ...)
Packit 6c4009
{
Packit 6c4009
  char *str;
Packit 6c4009
  va_list arg;
Packit 6c4009
Packit 6c4009
  recorded_error_count++;
Packit 6c4009
Packit 6c4009
  /* The existing behaviour is that even if you use --quiet, a fatal
Packit 6c4009
     error is always printed and terminates the process.  */
Packit 6c4009
  if (!be_quiet || status != 0)
Packit 6c4009
    {
Packit 6c4009
      struct locale_state ls;
Packit 6c4009
      int ret;
Packit 6c4009
Packit 6c4009
      va_start (arg, format);
Packit 6c4009
      ls = push_locale ();
Packit 6c4009
Packit 6c4009
      ret = vasprintf (&str, format, arg);
Packit 6c4009
      if (ret == -1)
Packit 6c4009
        abort ();
Packit 6c4009
Packit 6c4009
      pop_locale (ls);
Packit 6c4009
      va_end (arg);
Packit 6c4009
Packit 6c4009
      error_at_line (status, errnum, filename, linenum, "[error] %s", str);
Packit 6c4009
Packit 6c4009
      free (str);
Packit 6c4009
    }
Packit 6c4009
}