[PATCH] locale: Fix localedef exit code [BZ #22292]
Florian Weimer
fweimer@redhat.com
Fri Oct 13 13:19:00 GMT 2017
On 10/13/2017 10:24 AM, Carlos O'Donell wrote:
> 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,
âfewer errorsâ (in case this makes it into the commit message.
The general approach of the patch looks okay to me. I expect that one
day, we might use the support/ infrastructure, potentially compiled for
the host, in these programs as well, but that's not a current priority.
> @@ -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);
runp->line fits on the preceding line (similar occurrences below).
> @@ -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'"));
Either turn this into a pure comment, or into a real warning.
> 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
> -#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);
> +}
Format string bug: This needs to to use error_at_line (0, 0, lr->fname,
lr->lineno, "%s", str). Missing error checking, and missing format
string attribute.
> 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
Missing empty line.
> +/* 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;
You could turn these into tentative definitions (and update the
comment). Then the main program does not have to define them.
> +/* Saved state of the current locale. */
> +struct locale_state
> +{
> + const char *cur_locale;
> +};
Drop the const for the change below.
> +/* 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);
> +}
The locale string returned by setlocale is only valid until the next
setlocale call, I think, so you need to use strdup and free for the
locale string. strdup and setlocale need error checking. Maybe
introduce xsetlocale?
> +/* 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);
> + }
> +}
These functions should not be inline and have printf/nonnull attributes.
fprintf has a format string bug, should use fputs. vasprintf needs
error checking.
> +
> +/* 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);
> + }
> +}
The status/errnum parameters are unused and should be removed (status in
particularly is conceptually unusable).
error has a format string bug, should use error (status, errnum, "%s", 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);
> + }
The condition needs to be !be_quiet || status != 0, otherwise be_quiet
also disables fatal errors. This applies to record_error_at_line, too.
Thanks,
Florian
More information about the Libc-alpha
mailing list