2001-08-16  Ulrich Drepper  <drepper@redhat.com>

	* misc/err.c: Handle wide oriented stderr.
This commit is contained in:
Ulrich Drepper 2001-08-16 17:51:43 +00:00
parent 8e2949409c
commit a26353616e
3 changed files with 329 additions and 18 deletions

View File

@ -1,3 +1,7 @@
2001-08-16 Ulrich Drepper <drepper@redhat.com>
* misc/err.c: Handle wide oriented stderr.
2001-08-14 Tom Rix <trix@redhat.com> 2001-08-14 Tom Rix <trix@redhat.com>
* iconv/gconv_cache.c (find_module): Add #ifndef STATIC_GCONV. * iconv/gconv_cache.c (find_module): Add #ifndef STATIC_GCONV.

View File

@ -1272,7 +1272,8 @@ This function @code{strerror_r} is a GNU extension and it is declared in
@comment ISO @comment ISO
@deftypefun void perror (const char *@var{message}) @deftypefun void perror (const char *@var{message})
This function prints an error message to the stream @code{stderr}; 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 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 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 messages or embedded newlines. Each error message begins with a capital
letter and does not include any terminating punctuation. letter and does not include any terminating punctuation.
@strong{Compatibility Note:} The @code{strerror} function is a new @strong{Compatibility Note:} The @code{strerror} function was introduced
feature of @w{ISO C}. Many older C systems do not support this function in @w{ISO C89}. Many older C systems do not support this function yet.
yet.
@cindex program name @cindex program name
@cindex name of running program @cindex name of running program
@ -1367,3 +1367,237 @@ open_sesame (char *name)
return stream; return stream;
@} @}
@end smallexample @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

View File

@ -1,5 +1,5 @@
/* err.c --- 4.4BSD utility functions for error messages. /* 4.4BSD utility functions for error messages.
Copyright (C) 1995, 1996, 1998 Free Software Foundation, Inc. Copyright (C) 1995, 1996, 1998, 2001 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or The GNU C Library is free software; you can redistribute it and/or
@ -25,6 +25,7 @@
#include <stdio.h> #include <stdio.h>
#ifdef USE_IN_LIBIO #ifdef USE_IN_LIBIO
# include <wchar.h>
# define flockfile(s) _IO_flockfile (s) # define flockfile(s) _IO_flockfile (s)
# define funlockfile(s) _IO_funlockfile (s) # define funlockfile(s) _IO_funlockfile (s)
#endif #endif
@ -39,15 +40,72 @@ extern char *__progname;
va_end (ap); \ 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 void
vwarnx (const char *format, __gnuc_va_list ap) vwarnx (const char *format, __gnuc_va_list ap)
{ {
flockfile (stderr); flockfile (stderr);
if (__progname) #ifdef USE_IN_LIBIO
fprintf (stderr, "%s: ", __progname); if (_IO_fwide (stderr, 0) > 0)
if (format) {
vfprintf (stderr, format, ap); fwprintf (stderr, L"%s: ", __progname);
putc_unlocked ('\n', stderr); 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); funlockfile (stderr);
} }
@ -57,15 +115,30 @@ vwarn (const char *format, __gnuc_va_list ap)
int error = errno; int error = errno;
flockfile (stderr); flockfile (stderr);
if (__progname) #ifdef USE_IN_LIBIO
fprintf (stderr, "%s: ", __progname); if (_IO_fwide (stderr, 0) > 0)
if (format)
{ {
vfprintf (stderr, format, ap); fwprintf (stderr, L"%s: ", __progname);
fputs_unlocked (": ", stderr); if (format)
{
convert_and_print (format, ap);
fputws_unlocked (L": ", stderr);
}
__set_errno (error);
fwprintf (stderr, L"%m\n");
}
else
#endif
{
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); funlockfile (stderr);
} }