mirror of
https://sourceware.org/git/glibc.git
synced 2025-01-03 08:11:08 +00:00
Update.
* misc/error.c (error): Handle wide oriented stderr stream correctly. * stdio-common/perror.c (perror): Implement according to standard. The stream orientation must not be changed if the stream was not oriented before the call. * stdio-common/Makefile (tests): Add tst-perror. * stdio-common/tst-perror.c: New file. See ChangeLog.12 for earlier changes.
This commit is contained in:
parent
c0fd6e1d64
commit
1fc0e33153
163
misc/error.c
163
misc/error.c
@ -26,6 +26,9 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <libintl.h>
|
||||
#ifdef _LIBC
|
||||
# include <wchar.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_VPRINTF || HAVE_DOPRNT || _LIBC
|
||||
# if __STDC__
|
||||
@ -117,12 +120,94 @@ private_strerror (errnum)
|
||||
# endif /* HAVE_STRERROR_R */
|
||||
#endif /* not _LIBC */
|
||||
|
||||
|
||||
#ifdef VA_START
|
||||
static void
|
||||
error_tail (int status, int errnum, const char *message, va_list args)
|
||||
{
|
||||
# if HAVE_VPRINTF || _LIBC
|
||||
# ifdef _LIBC
|
||||
if (_IO_fwide (stderr, 0) > 0)
|
||||
{
|
||||
# define ALLOCA_LIMIT 2000
|
||||
size_t len = strlen (message) + 1;
|
||||
wchar_t *wmessage = NULL;
|
||||
mbstate_t st;
|
||||
size_t res;
|
||||
const char *tmp;
|
||||
|
||||
do
|
||||
{
|
||||
if (len < ALLOCA_LIMIT)
|
||||
wmessage = (wchar_t *) alloca (len * sizeof (wchar_t));
|
||||
else
|
||||
{
|
||||
if (wmessage != NULL && len / 2 < ALLOCA_LIMIT)
|
||||
wmessage = NULL;
|
||||
|
||||
wmessage = (wchar_t *) realloc (wmessage,
|
||||
len * sizeof (wchar_t));
|
||||
|
||||
if (wmessage == NULL)
|
||||
{
|
||||
fputws (L"out of memory\n", stderr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
memset (&st, '\0', sizeof (st));
|
||||
tmp =message;
|
||||
}
|
||||
while ((res = mbsrtowcs (wmessage, &tmp, len, &st)) == len);
|
||||
|
||||
if (res == (size_t) -1)
|
||||
/* The string cannot be converted. */
|
||||
wmessage = (wchar_t *) L"???";
|
||||
|
||||
vfwprintf (stderr, wmessage, args);
|
||||
}
|
||||
else
|
||||
# endif
|
||||
vfprintf (stderr, message, args);
|
||||
# else
|
||||
_doprnt (message, args, stderr);
|
||||
# endif
|
||||
va_end (args);
|
||||
|
||||
++error_message_count;
|
||||
if (errnum)
|
||||
{
|
||||
#if defined HAVE_STRERROR_R || _LIBC
|
||||
char errbuf[1024];
|
||||
char *s = __strerror_r (errnum, errbuf, sizeof errbuf);
|
||||
# ifdef _LIBC
|
||||
if (_IO_fwide (stderr, 0) > 0)
|
||||
fwprintf (stderr, L": %s", s);
|
||||
else
|
||||
# endif
|
||||
fprintf (stderr, ": %s", s);
|
||||
#else
|
||||
fprintf (stderr, ": %s", strerror (errnum));
|
||||
#endif
|
||||
}
|
||||
#ifdef _LIBC
|
||||
if (_IO_fwide (stderr, 0) > 0)
|
||||
putwc (L'\n', stderr);
|
||||
else
|
||||
#endif
|
||||
putc ('\n', stderr);
|
||||
fflush (stderr);
|
||||
if (status)
|
||||
exit (status);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Print the program name and error message MESSAGE, which is a printf-style
|
||||
format string with optional args.
|
||||
If ERRNUM is nonzero, print its corresponding system error message.
|
||||
Exit with status STATUS if it is nonzero. */
|
||||
/* VARARGS */
|
||||
|
||||
void
|
||||
#if defined VA_START && __STDC__
|
||||
error (int status, int errnum, const char *message, ...)
|
||||
@ -139,37 +224,38 @@ error (status, errnum, message, va_alist)
|
||||
#endif
|
||||
|
||||
fflush (stdout);
|
||||
#ifdef _LIBC
|
||||
flockfile (stderr);
|
||||
#endif
|
||||
if (error_print_progname)
|
||||
(*error_print_progname) ();
|
||||
else
|
||||
fprintf (stderr, "%s: ", program_name);
|
||||
{
|
||||
#ifdef _LIBC
|
||||
if (_IO_fwide (stderr, 0) > 0)
|
||||
fwprintf (stderr, L"%s: ", program_name);
|
||||
else
|
||||
#endif
|
||||
fprintf (stderr, "%s: ", program_name);
|
||||
}
|
||||
|
||||
#ifdef VA_START
|
||||
VA_START (args, message);
|
||||
# if HAVE_VPRINTF || _LIBC
|
||||
vfprintf (stderr, message, args);
|
||||
# else
|
||||
_doprnt (message, args, stderr);
|
||||
error_tail (status, errnum, message, args);
|
||||
# ifdef _LIBC
|
||||
funlockfile (stderr);
|
||||
# endif
|
||||
va_end (args);
|
||||
#else
|
||||
fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
|
||||
#endif
|
||||
|
||||
++error_message_count;
|
||||
if (errnum)
|
||||
{
|
||||
#if defined HAVE_STRERROR_R || _LIBC
|
||||
char errbuf[1024];
|
||||
fprintf (stderr, ": %s", __strerror_r (errnum, errbuf, sizeof errbuf));
|
||||
#else
|
||||
fprintf (stderr, ": %s", strerror (errnum));
|
||||
#endif
|
||||
}
|
||||
fprintf (stderr, ": %s", strerror (errnum));
|
||||
putc ('\n', stderr);
|
||||
fflush (stderr);
|
||||
if (status)
|
||||
exit (status);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Sometimes we want to have at most one error per line. This
|
||||
@ -199,8 +285,9 @@ error_at_line (status, errnum, file_name, line_number, message, va_alist)
|
||||
static const char *old_file_name;
|
||||
static unsigned int old_line_number;
|
||||
|
||||
if (old_line_number == line_number &&
|
||||
(file_name == old_file_name || !strcmp (old_file_name, file_name)))
|
||||
if (old_line_number == line_number
|
||||
&& (file_name == old_file_name
|
||||
|| strcmp (old_file_name, file_name) == 0))
|
||||
/* Simply return and print nothing. */
|
||||
return;
|
||||
|
||||
@ -209,40 +296,48 @@ error_at_line (status, errnum, file_name, line_number, message, va_alist)
|
||||
}
|
||||
|
||||
fflush (stdout);
|
||||
#ifdef _LIBC
|
||||
flockfile (stderr);
|
||||
#endif
|
||||
if (error_print_progname)
|
||||
(*error_print_progname) ();
|
||||
else
|
||||
fprintf (stderr, "%s:", program_name);
|
||||
{
|
||||
#ifdef _LIBC
|
||||
if (_IO_fwide (stderr, 0) > 0)
|
||||
fwprintf (stderr, L"%s: ", program_name);
|
||||
else
|
||||
#endif
|
||||
fprintf (stderr, "%s:", program_name);
|
||||
}
|
||||
|
||||
if (file_name != NULL)
|
||||
fprintf (stderr, "%s:%d: ", file_name, line_number);
|
||||
{
|
||||
#ifdef _LIBC
|
||||
if (_IO_fwide (stderr, 0) > 0)
|
||||
fwprintf (stderr, L"%s:%d: ", file_name, line_number);
|
||||
else
|
||||
#endif
|
||||
fprintf (stderr, "%s:%d: ", file_name, line_number);
|
||||
}
|
||||
|
||||
#ifdef VA_START
|
||||
VA_START (args, message);
|
||||
# if HAVE_VPRINTF || _LIBC
|
||||
vfprintf (stderr, message, args);
|
||||
# else
|
||||
_doprnt (message, args, stderr);
|
||||
error_tail (status, errnum, message, args);
|
||||
# ifdef _LIBC
|
||||
funlockfile (stderr);
|
||||
# endif
|
||||
va_end (args);
|
||||
#else
|
||||
fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
|
||||
#endif
|
||||
|
||||
++error_message_count;
|
||||
if (errnum)
|
||||
{
|
||||
#if defined HAVE_STRERROR_R || _LIBC
|
||||
char errbuf[1024];
|
||||
fprintf (stderr, ": %s", __strerror_r (errnum, errbuf, sizeof errbuf));
|
||||
#else
|
||||
fprintf (stderr, ": %s", strerror (errnum));
|
||||
#endif
|
||||
}
|
||||
fprintf (stderr, ": %s", strerror (errnum));
|
||||
putc ('\n', stderr);
|
||||
fflush (stderr);
|
||||
if (status)
|
||||
exit (status);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _LIBC
|
||||
|
@ -55,7 +55,7 @@ tests := tstscanf test_rdwr test-popen tstgetln test-fseek \
|
||||
tfformat tiformat tllformat tstdiomisc tst-printfsz tst-wc-printf \
|
||||
scanf1 scanf2 scanf3 scanf4 scanf5 scanf7 scanf8 scanf9 scanf10 \
|
||||
scanf12 tst-tmpnam tst-cookie tst-obprintf tst-sscanf tst-swprintf \
|
||||
tst-fseek tst-fmemopen test-vfprintf tst-gets
|
||||
tst-fseek tst-fmemopen test-vfprintf tst-gets tst-perror
|
||||
|
||||
test-srcs = tst-unbputc tst-printf
|
||||
|
||||
|
@ -19,13 +19,14 @@
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <wchar.h>
|
||||
#ifdef USE_IN_LIBIO
|
||||
# include "libioP.h"
|
||||
#endif
|
||||
|
||||
/* Print a line on stderr consisting of the text in S, a colon, a space,
|
||||
a message describing the meaning of the contents of `errno' and a newline.
|
||||
If S is NULL or "", the colon and space are omitted. */
|
||||
void
|
||||
perror (const char *s)
|
||||
static void
|
||||
perror_internal (FILE *fp, const char *s)
|
||||
{
|
||||
char buf[1024];
|
||||
int errnum = errno;
|
||||
@ -40,9 +41,47 @@ perror (const char *s)
|
||||
errstring = __strerror_r (errnum, buf, sizeof buf);
|
||||
|
||||
#ifdef USE_IN_LIBIO
|
||||
if (_IO_fwide (stderr, 0) > 0)
|
||||
(void) fwprintf (stderr, L"%s%s%s\n", s, colon, errstring);
|
||||
if (_IO_fwide (fp, 0) > 0)
|
||||
(void) fwprintf (fp, L"%s%s%s\n", s, colon, errstring);
|
||||
else
|
||||
#endif
|
||||
(void) fprintf (stderr, "%s%s%s\n", s, colon, errstring);
|
||||
(void) fprintf (fp, "%s%s%s\n", s, colon, errstring);
|
||||
}
|
||||
|
||||
|
||||
/* Print a line on stderr consisting of the text in S, a colon, a space,
|
||||
a message describing the meaning of the contents of `errno' and a newline.
|
||||
If S is NULL or "", the colon and space are omitted. */
|
||||
void
|
||||
perror (const char *s)
|
||||
{
|
||||
FILE *fp;
|
||||
int fd = -1;
|
||||
|
||||
/* The standard says that 'perror' must not change the orientation
|
||||
of the stream. What is supposed to happen when the stream isn't
|
||||
oriented yet? In this case we'll create a new stream which is
|
||||
using the same underlying file descriptor. */
|
||||
if (__builtin_expect (_IO_fwide (stderr, 0) != 0, 1)
|
||||
|| fileno_unlocked (stderr) == -1
|
||||
|| (fd = dup (fileno_unlocked (stderr))) == -1
|
||||
|| (fp = fdopen (fd, "w+")) == NULL)
|
||||
{
|
||||
if (__builtin_expect (fd != -1, 0))
|
||||
close (fd);
|
||||
|
||||
/* Use standard error as is. */
|
||||
perror_internal (stderr, s);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We don't have to do any special hacks regarding the file
|
||||
position. Since the stderr stream wasn't used so far we just
|
||||
write to the descriptor. */
|
||||
perror_internal (fp, s);
|
||||
/* Close the stream. */
|
||||
fclose (fp);
|
||||
|
||||
((_IO_FILE *) stderr)->_offset = _IO_pos_BAD;
|
||||
}
|
||||
}
|
||||
|
154
stdio-common/tst-perror.c
Normal file
154
stdio-common/tst-perror.c
Normal file
@ -0,0 +1,154 @@
|
||||
/* Test of perror.
|
||||
Contributed by Ulrich Drepper <drepper@redhat.com>, 2001.
|
||||
To be used only for testing glibc. */
|
||||
|
||||
#include <errno.h>
|
||||
#include <error.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <wchar.h>
|
||||
|
||||
|
||||
#define MB_EXP \
|
||||
"null mode test 1: Invalid or incomplete multibyte or wide character\n" \
|
||||
"multibyte string\n" \
|
||||
"<0 mode test: Invalid argument\n"
|
||||
#define MB_EXP_LEN (sizeof (MB_EXP) - 1)
|
||||
|
||||
#define WC_EXP \
|
||||
"null mode test 2: Invalid or incomplete multibyte or wide character\n" \
|
||||
"wide string\n" \
|
||||
">0 mode test: Invalid argument\n"
|
||||
#define WC_EXP_LEN (sizeof (WC_EXP) - 1)
|
||||
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
int fd;
|
||||
char fname[] = "/tmp/tst-perror.XXXXXX";
|
||||
int result = 0;
|
||||
char buf[200];
|
||||
ssize_t n;
|
||||
|
||||
fd = mkstemp (fname);
|
||||
if (fd == -1)
|
||||
error (EXIT_FAILURE, errno, "cannot create temporary file");
|
||||
|
||||
/* Make sure the file gets removed. */
|
||||
unlink (fname);
|
||||
|
||||
fclose (stderr);
|
||||
|
||||
if (dup2 (fd, 2) == -1)
|
||||
{
|
||||
printf ("cannot create file descriptor 2: %m\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
stderr = fdopen (2, "w");
|
||||
if (stderr == NULL)
|
||||
{
|
||||
printf ("fdopen failed: %m\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (fwide (stderr, 0) != 0)
|
||||
{
|
||||
printf ("stderr not initially in mode 0\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
errno = EILSEQ;
|
||||
perror ("null mode test 1");
|
||||
|
||||
if (fwide (stderr, 0) != 0)
|
||||
{
|
||||
puts ("perror changed the mode from 0");
|
||||
result = 1;
|
||||
}
|
||||
|
||||
fputs ("multibyte string\n", stderr);
|
||||
|
||||
if (fwide (stderr, 0) >= 0)
|
||||
{
|
||||
puts ("fputs didn't set orientation to narrow");
|
||||
result = 1;
|
||||
}
|
||||
|
||||
errno = EINVAL;
|
||||
perror ("<0 mode test");
|
||||
|
||||
fclose (stderr);
|
||||
|
||||
lseek (fd, 0, SEEK_SET);
|
||||
n = read (fd, buf, sizeof (buf));
|
||||
if (n != MB_EXP_LEN || memcmp (buf, MB_EXP, MB_EXP_LEN) != 0)
|
||||
{
|
||||
printf ("multibyte test failed. Expected:\n%s\nGot:\n%.*s\n",
|
||||
MB_EXP, (int) n, buf);
|
||||
result = 1;
|
||||
}
|
||||
else
|
||||
puts ("multibyte test succeeded");
|
||||
|
||||
lseek (fd, 0, SEEK_SET);
|
||||
ftruncate (fd, 0);
|
||||
|
||||
if (dup2 (fd, 2) == -1)
|
||||
{
|
||||
printf ("cannot create file descriptor 2: %m\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
stderr = fdopen (2, "w");
|
||||
if (stderr == NULL)
|
||||
{
|
||||
printf ("fdopen failed: %m\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (fwide (stderr, 0) != 0)
|
||||
{
|
||||
printf ("stderr not initially in mode 0\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
errno = EILSEQ;
|
||||
perror ("null mode test 2");
|
||||
|
||||
if (fwide (stderr, 0) != 0)
|
||||
{
|
||||
puts ("perror changed the mode from 0");
|
||||
result = 1;
|
||||
}
|
||||
|
||||
fputws (L"wide string\n", stderr);
|
||||
|
||||
if (fwide (stderr, 0) <= 0)
|
||||
{
|
||||
puts ("fputws didn't set orientation to wide");
|
||||
result = 1;
|
||||
}
|
||||
|
||||
errno = EINVAL;
|
||||
perror (">0 mode test");
|
||||
|
||||
fclose (stderr);
|
||||
|
||||
lseek (fd, 0, SEEK_SET);
|
||||
n = read (fd, buf, sizeof (buf));
|
||||
if (n != WC_EXP_LEN || memcmp (buf, WC_EXP, WC_EXP_LEN) != 0)
|
||||
{
|
||||
printf ("wide test failed. Expected:\n%s\nGot:\n%.*s\n",
|
||||
WC_EXP, (int) n, buf);
|
||||
result = 1;
|
||||
}
|
||||
else
|
||||
puts ("wide test succeeded");
|
||||
|
||||
close (fd);
|
||||
|
||||
return result;
|
||||
}
|
Loading…
Reference in New Issue
Block a user