From a26353616e67507deb0ecd3d9020115e7f594948 Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Thu, 16 Aug 2001 17:51:43 +0000 Subject: [PATCH] Update. 2001-08-16 Ulrich Drepper * misc/err.c: Handle wide oriented stderr. --- ChangeLog | 4 + manual/errno.texi | 242 +++++++++++++++++++++++++++++++++++++++++++++++++++++- misc/err.c | 101 +++++++++++++++++++---- 3 files changed, 329 insertions(+), 18 deletions(-) diff --git a/ChangeLog b/ChangeLog index ec71dce..11c55ea 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2001-08-16 Ulrich Drepper + + * misc/err.c: Handle wide oriented stderr. + 2001-08-14 Tom Rix * iconv/gconv_cache.c (find_module): Add #ifndef STATIC_GCONV. diff --git a/manual/errno.texi b/manual/errno.texi index 5abb823..ee0a621 100644 --- a/manual/errno.texi +++ b/manual/errno.texi @@ -1272,7 +1272,8 @@ This function @code{strerror_r} is a GNU extension and it is declared in @comment ISO @deftypefun void perror (const char *@var{message}) This function prints an error message to the stream @code{stderr}; -see @ref{Standard Streams}. +see @ref{Standard Streams}. The orientation of @code{stderr} is not +changed. If you call @code{perror} with a @var{message} that is either a null pointer or an empty string, @code{perror} just prints the error message @@ -1292,9 +1293,8 @@ GNU system, the messages are fairly short; there are no multi-line messages or embedded newlines. Each error message begins with a capital letter and does not include any terminating punctuation. -@strong{Compatibility Note:} The @code{strerror} function is a new -feature of @w{ISO C}. Many older C systems do not support this function -yet. +@strong{Compatibility Note:} The @code{strerror} function was introduced +in @w{ISO C89}. Many older C systems do not support this function yet. @cindex program name @cindex name of running program @@ -1367,3 +1367,237 @@ open_sesame (char *name) return stream; @} @end smallexample + +Using @code{perror} has the advantage that the function is portable and +available on all systems implementing @w{ISO C}. But often the text +@code{perror} generates is not what is wanted and there is no way to +extend or change what @code{perror} does. The GNU coding standard, for +instance, requires error messages to be preceded by the program name and +programs which read some input files should should provide information +about the input file name and the line number in case an error is +encountered while reading the file. For these occasions there are two +functions available which are widely used throughout the GNU project. +These functions are declared in @file{error.h}. + +@comment error.h +@comment GNU +@deftypefun void error (int @var{status}, int @var{errnum}, const char *@var{format}, @dots{}) +The @code{error} function can be used to report general problems during +program execution. The @var{format} argument is a format string just +like those given to the @code{printf} family of functions. The +arguments required for the format can follow the @var{format} parameter. +Just like @code{perror}, @code{error} also can report an error code in +textual form. But unlike @code{perror} the error value is explicitly +passed to the function in the @var{errnum} parameter. This elimintates +the problem mentioned above that the error reporting function must be +called immediately after the function causing the error since otherwise +@code{errno} might have a different value. + +The @code{error} prints first the program name. If the application +defined a global variable @code{error_print_progname} and points it to a +function this function will be called to print the program name. +Otherwise the string from the global variable @code{program_name} is +used. The program name is followed by a colon and a space which in turn +is followed by the output produced by the format string. If the +@var{errnum} parameter is non-zero the format string output is followed +by a colon and a space, followed by the error message for the error code +@var{errnum}. In any case is the output terminated with a newline. + +The output is directed to the @code{stderr} stream. If the +@code{stderr} wasn't oriented before the call it will be narrow-oriented +afterwards. + +The function will return unless the @var{status} parameter has a +non-zero value. In this case the function will call @code{exit} with +the @var{status} value for its parameter and therefore never return. If +@code{error} returns the global variable @code{error_message_count} is +incremented by one to keep track of the number of errors reported. +@end deftypefun + +@comment error.h +@comment GNU +@deftypefun void error_at_line (int @var{status}, int @var{errnum}, const char *@var{fname}, unsigned int @var{lineno}, const char *@var{format}, @dots{}) + +The @code{error_at_line} function is very similar to the @code{error} +function. The only difference are the additional parameters @var{fname} +and @var{lineno}. The handling of the other parameters is identical to +that of @code{error} except that between the program name and the string +generated by the format string additional text is inserted. + +Directly following the program name a colon, followed by the file name +pointer to by @var{fname}, another colon, and a value of @var{lineno} is +printed. + +This additional output of course is meant to be used to locate an error +in an input file (like a programming language source code file etc). + +If the global variable @code{error_one_per_line} is set to a non-zero +value @code{error_at_line} will avoid printing consecutive messages for +the same file anem line. Repetition which are not directly following +each other are not caught. + +Just like @code{error} this function only returned if @var{status} is +zero. Otherwise @code{exit} is called with the non-zero value. If +@code{error} returns the global variable @code{error_message_count} is +incremented by one to keep track of the number of errors reported. +@end deftypefun + +As mentioned above the @code{error} and @code{error_at_line} functions +can be customized by defining a variable named +@code{error_print_progname}. + +@comment error.h +@comment GNU +@deftypevar {void (*} error_print_progname ) (void) +If the @code{error_print_progname} variable is defined to a non-zero +value the function pointed to is called by @code{error} or +@code{error_at_line}. It is expected to print the program name or do +something similarly useful. + +The function is expected to be print to the @code{stderr} stream and +must be able to handle whatever orientation the stream has. + +The variable is global and shared by all threads. +@end deftypevar + +@comment error.h +@comment GNU +@deftypevar {unsigned int} error_message_count +The @code{error_message_count} variable is incremented whenever one of +the functions @code{error} or @code{error_at_line} returns. The +variable is global and shared by all threads. +@end deftypevar + +@comment error.h +@comment GNU +@deftypevar int error_one_per_line +The @code{error_one_per_line} variable influences only +@code{error_at_line}. Normally the @code{error_at_line} function +creates output for every invocation. If @code{error_one_per_line} is +set to a non-zero value @code{error_at_line} keeps track of the last +file name and line number for which an error was reported and avoid +directly following messages for the same file and line. This variable +is global and shared by all threads. +@end deftypevar + +@noindent +A program which read some input file and reports errors in it could look +like this: + +@smallexample +@{ + char *line = NULL; + size_t len = 0; + unsigned int lineno = 0; + + error_message_count = 0; + while (! feof_unlocked (fp)) + @{ + ssize_t n = getline (&line, &len, fp); + if (n <= 0) + /* @r{End of file or error.} */ + break; + ++lineno; + + /* @r{Process the line.} */ + @dots{} + + if (@r{Detect error in line}) + error_at_line (0, errval, filename, lineno, + "some error text %s", some_variable); + @} + + if (error_message_count != 0) + error (EXIT_FAILURE, 0, "%u errors found", error_message_count); +@} +@end smallexample + +@code{error} and @code{error_at_line} are clearly the functions of +choice and enable the programmer to write applications which follow the +GNU coding standard. The GNU libc additionally contains functions which +are used in BSD for the same purpose. These functions are declared in +@file{err.h}. It is generally advised to not use these functions. They +are included only for compatibility. + +@comment err.h +@comment BSD +@deftypefun void warn (const char *@var{format}, @dots{}) +The @code{warn} function is roughly equivalent to a call like +@smallexample + error (0, errno, format, @r{the parameters}) +@end smallexample +@noindent +except that the global variables @code{error} respects and modifies +are not used. +@end deftypefun + +@comment err.h +@comment BSD +@deftypefun void vwarn (const char *@var{format}, va_list) +The @code{vwarn} function is just like @code{warn} except that the +parameters for the handling of the format string @var{format} are passed +in as an value of type @code{va_list}. +@end deftypefun + +@comment err.h +@comment BSD +@deftypefun void warnx (const char *@var{format}, @dots{}) +The @code{warnx} function is roughly equivalent to a call like +@smallexample + error (0, 0, format, @r{the parameters}) +@end smallexample +@noindent +except that the global variables @code{error} respects and modifies +are not used. The difference to @code{warn} is that no error number +string is printed. +@end deftypefun + +@comment err.h +@comment BSD +@deftypefun void vwarnx (const char *@var{format}, va_list) +The @code{vwarnx} function is just like @code{warnx} except that the +parameters for the handling of the format string @var{format} are passed +in as an value of type @code{va_list}. +@end deftypefun + +@comment err.h +@comment BSD +@deftypefun void err (int @var{status}, const char *@var{format}, @dots{}) +The @code{err} function is roughly equivalent to a call like +@smallexample + error (status, errno, format, @r{the parameters}) +@end smallexample +@noindent +except that the global variables @code{error} respects and modifies +are not used and that the program is exited even if @var{status} is zero. +@end deftypefun + +@comment err.h +@comment BSD +@deftypefun void verr (int @var{status}, const char *@var{format}, va_list) +The @code{verr} function is just like @code{err} except that the +parameters for the handling of the format string @var{format} are passed +in as an value of type @code{va_list}. +@end deftypefun + +@comment err.h +@comment BSD +@deftypefun void errx (int @var{status}, const char *@var{format}, @dots{}) +The @code{errx} function is roughly equivalent to a call like +@smallexample + error (status, 0, format, @r{the parameters}) +@end smallexample +@noindent +except that the global variables @code{error} respects and modifies +are not used and that the program is exited even if @var{status} +is zero. The difference to @code{err} is that no error number +string is printed. +@end deftypefun + +@comment err.h +@comment BSD +@deftypefun void verrx (int @var{status}, const char *@var{format}, va_list) +The @code{verrx} function is just like @code{errx} except that the +parameters for the handling of the format string @var{format} are passed +in as an value of type @code{va_list}. +@end deftypefun diff --git a/misc/err.c b/misc/err.c index 4e1d43b..dc7025c 100644 --- a/misc/err.c +++ b/misc/err.c @@ -1,5 +1,5 @@ -/* err.c --- 4.4BSD utility functions for error messages. - Copyright (C) 1995, 1996, 1998 Free Software Foundation, Inc. +/* 4.4BSD utility functions for error messages. + Copyright (C) 1995, 1996, 1998, 2001 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -25,6 +25,7 @@ #include #ifdef USE_IN_LIBIO +# include # define flockfile(s) _IO_flockfile (s) # define funlockfile(s) _IO_funlockfile (s) #endif @@ -39,15 +40,72 @@ extern char *__progname; va_end (ap); \ } +#ifdef USE_IN_LIBIO +static void +convert_and_print (const char *format, __gnuc_va_list ap) +{ +# define ALLOCA_LIMIT 2000 + size_t len; + wchar_t *wformat = NULL; + mbstate_t st; + size_t res; + const char *tmp; + + if (format == NULL) + return; + + len = strlen (format) + 1; + + do + { + if (len < ALLOCA_LIMIT) + wformat = (wchar_t *) alloca (len * sizeof (wchar_t)); + else + { + if (wformat != NULL && len / 2 < ALLOCA_LIMIT) + wformat = NULL; + + wformat = (wchar_t *) realloc (wformat, len * sizeof (wchar_t)); + + if (wformat == NULL) + { + fputws (L"out of memory\n", stderr); + return; + } + } + + memset (&st, '\0', sizeof (st)); + tmp =format; + } + while ((res = mbsrtowcs (wformat, &tmp, len, &st)) == len); + + if (res == (size_t) -1) + /* The string cannot be converted. */ + wformat = (wchar_t *) L"???"; + + vfwprintf (stderr, wformat, ap); +} +#endif + void vwarnx (const char *format, __gnuc_va_list ap) { flockfile (stderr); - if (__progname) - fprintf (stderr, "%s: ", __progname); - if (format) - vfprintf (stderr, format, ap); - putc_unlocked ('\n', stderr); +#ifdef USE_IN_LIBIO + if (_IO_fwide (stderr, 0) > 0) + { + fwprintf (stderr, L"%s: ", __progname); + convert_and_print (format, ap); + putwc_unlocked (L'\n', stderr); + } + else +#endif + { + fprintf (stderr, "%s: ", __progname); + if (format) + vfprintf (stderr, format, ap); + putc_unlocked ('\n', stderr); + } funlockfile (stderr); } @@ -57,15 +115,30 @@ vwarn (const char *format, __gnuc_va_list ap) int error = errno; flockfile (stderr); - if (__progname) - fprintf (stderr, "%s: ", __progname); - if (format) +#ifdef USE_IN_LIBIO + if (_IO_fwide (stderr, 0) > 0) + { + fwprintf (stderr, L"%s: ", __progname); + if (format) + { + convert_and_print (format, ap); + fputws_unlocked (L": ", stderr); + } + __set_errno (error); + fwprintf (stderr, L"%m\n"); + } + else +#endif { - vfprintf (stderr, format, ap); - fputs_unlocked (": ", stderr); + fprintf (stderr, "%s: ", __progname); + if (format) + { + vfprintf (stderr, format, ap); + fputs_unlocked (": ", stderr); + } + __set_errno (error); + fprintf (stderr, "%m\n"); } - __set_errno (error); - fprintf (stderr, "%m\n"); funlockfile (stderr); } -- 2.7.4