(root)/
glibc-2.38/
locale/
programs/
record-status.c
       1  /* Functions for recorded errors, warnings, and verbose messages.
       2     Copyright (C) 1998-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     This program is free software; you can redistribute it and/or modify
       6     it under the terms of the GNU General Public License as published
       7     by the Free Software Foundation; version 2 of the License, or
       8     (at your option) any later version.
       9  
      10     This program is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13     GNU General Public License for more details.
      14  
      15     You should have received a copy of the GNU General Public License
      16     along with this program; if not, see <https://www.gnu.org/licenses/>.  */
      17  
      18  #include <stdio.h>
      19  #include <stdlib.h>
      20  #include <stdarg.h>
      21  #include <stdbool.h>
      22  #include <string.h>
      23  #include <error.h>
      24  #include <errno.h>
      25  #include <locale.h>
      26  
      27  #include "record-status.h"
      28  
      29  /* Warnings recorded by record_warnings.  */
      30  int recorded_warning_count;
      31  
      32  /* Errors recorded by record_errors.  */
      33  int recorded_error_count;
      34  
      35  /* If not zero suppress warnings and information messages.  */
      36  int be_quiet;
      37  
      38  /* If not zero give a lot more messages.  */
      39  int verbose;
      40  
      41  /* Warnings which can be disabled:  */
      42  /* By default we check the character map for ASCII compatibility.  */
      43  bool warn_ascii = true;
      44  /* By default we check that the international currency symbol matches a
      45     known country code.  */
      46  bool warn_int_curr_symbol = true;
      47  
      48  /* Alter the current locale to match the locale configured by the
      49     user, and return the previous saved state.  */
      50  struct locale_state
      51  push_locale (void)
      52  {
      53    int saved_errno;
      54    const char *orig;
      55    char *copy = NULL;
      56  
      57    saved_errno = errno;
      58  
      59    orig = setlocale (LC_CTYPE, NULL);
      60    if (orig == NULL)
      61      error (0, 0, "failed to read locale!");
      62  
      63    if (setlocale (LC_CTYPE, "") == NULL)
      64      error (0, 0, "failed to set locale!");
      65  
      66    errno = saved_errno;
      67  
      68    if (orig != NULL)
      69      copy = strdup (orig);
      70  
      71    /* We will return either a valid locale or NULL if we failed
      72       to save the locale.  */
      73    return (struct locale_state) { .cur_locale = copy };
      74  }
      75  
      76  /* Use the saved state to restore the locale.  */
      77  void
      78  pop_locale (struct locale_state ls)
      79  {
      80    const char *set = NULL;
      81    /* We might have failed to save the locale, so only attempt to
      82       restore a validly saved non-NULL locale.  */
      83    if (ls.cur_locale != NULL)
      84      {
      85        set = setlocale (LC_CTYPE, ls.cur_locale);
      86        if (set == NULL)
      87  	error (0, 0, "failed to restore %s locale!", ls.cur_locale);
      88  
      89        free (ls.cur_locale);
      90      }
      91  }
      92  
      93  /* Wrapper to print verbose informative messages.
      94     Verbose messages are only printed if --verbose
      95     is in effect and --quiet is not.  */
      96  void
      97  __attribute__ ((__format__ (__printf__, 2, 3), nonnull (1, 2), unused))
      98  record_verbose (FILE *stream, const char *format, ...)
      99  {
     100    char *str;
     101    va_list arg;
     102  
     103    if (!verbose)
     104      return;
     105  
     106    if (!be_quiet)
     107      {
     108        struct locale_state ls;
     109        int ret;
     110  
     111        va_start (arg, format);
     112        ls = push_locale ();
     113  
     114        ret = vasprintf (&str, format, arg);
     115        if (ret == -1)
     116  	abort ();
     117  
     118        pop_locale (ls);
     119        va_end (arg);
     120  
     121        fprintf (stream, "[verbose] %s\n", str);
     122  
     123        free (str);
     124      }
     125  }
     126  
     127  /* Wrapper to print warning messages.  We keep track of how
     128     many were called because this effects our exit code.
     129     Nothing is printed if --quiet is in effect, but warnings
     130     are always counted.  */
     131  void
     132  __attribute__ ((__format__ (__printf__, 1, 2), nonnull (1), unused))
     133  record_warning (const char *format, ...)
     134  {
     135    char *str;
     136    va_list arg;
     137  
     138    recorded_warning_count++;
     139  
     140    if (!be_quiet)
     141      {
     142        struct locale_state ls;
     143        int ret;
     144  
     145        va_start (arg, format);
     146        ls = push_locale ();
     147  
     148        ret = vasprintf (&str, format, arg);
     149        if (ret == -1)
     150  	abort ();
     151  
     152        pop_locale (ls);
     153        va_end (arg);
     154  
     155        fprintf (stderr, "[warning] %s\n", str);
     156  
     157        free (str);
     158      }
     159  }
     160  
     161  /* Wrapper to print error messages.  We keep track of how
     162     many were called because this effects our exit code.
     163     Nothing is printed if --quiet is in effect, but errors
     164     are always counted, and fatal errors always exit the
     165     program.  */
     166  void
     167  __attribute__ ((__format__ (__printf__, 3, 4), nonnull (3), unused))
     168  record_error (int status, int errnum, const char *format, ...)
     169  {
     170    char *str;
     171    va_list arg;
     172  
     173    recorded_error_count++;
     174  
     175    /* The existing behaviour is that even if you use --quiet, a fatal
     176       error is always printed and terminates the process.  */
     177    if (!be_quiet || status != 0)
     178      {
     179        struct locale_state ls;
     180        int ret;
     181  
     182        va_start (arg, format);
     183        ls = push_locale ();
     184  
     185        ret = vasprintf (&str, format, arg);
     186        if (ret == -1)
     187          abort ();
     188  
     189        pop_locale (ls);
     190        va_end (arg);
     191  
     192        error (status, errnum, "[error] %s", str);
     193  
     194        free (str);
     195      }
     196  }
     197  /* ... likewise for error_at_line.  */
     198  void
     199  __attribute__ ((__format__ (__printf__, 5, 6), nonnull (3, 5), unused))
     200  record_error_at_line (int status, int errnum, const char *filename,
     201  		      unsigned int linenum, const char *format, ...)
     202  {
     203    char *str;
     204    va_list arg;
     205  
     206    recorded_error_count++;
     207  
     208    /* The existing behaviour is that even if you use --quiet, a fatal
     209       error is always printed and terminates the process.  */
     210    if (!be_quiet || status != 0)
     211      {
     212        struct locale_state ls;
     213        int ret;
     214  
     215        va_start (arg, format);
     216        ls = push_locale ();
     217  
     218        ret = vasprintf (&str, format, arg);
     219        if (ret == -1)
     220          abort ();
     221  
     222        pop_locale (ls);
     223        va_end (arg);
     224  
     225        error_at_line (status, errnum, filename, linenum, "[error] %s", str);
     226  
     227        free (str);
     228      }
     229  }