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 <stdio.h>
|
||||||
#include <libintl.h>
|
#include <libintl.h>
|
||||||
|
#ifdef _LIBC
|
||||||
|
# include <wchar.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#if HAVE_VPRINTF || HAVE_DOPRNT || _LIBC
|
#if HAVE_VPRINTF || HAVE_DOPRNT || _LIBC
|
||||||
# if __STDC__
|
# if __STDC__
|
||||||
@ -117,12 +120,94 @@ private_strerror (errnum)
|
|||||||
# endif /* HAVE_STRERROR_R */
|
# endif /* HAVE_STRERROR_R */
|
||||||
#endif /* not _LIBC */
|
#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
|
/* Print the program name and error message MESSAGE, which is a printf-style
|
||||||
format string with optional args.
|
format string with optional args.
|
||||||
If ERRNUM is nonzero, print its corresponding system error message.
|
If ERRNUM is nonzero, print its corresponding system error message.
|
||||||
Exit with status STATUS if it is nonzero. */
|
Exit with status STATUS if it is nonzero. */
|
||||||
/* VARARGS */
|
/* VARARGS */
|
||||||
|
|
||||||
void
|
void
|
||||||
#if defined VA_START && __STDC__
|
#if defined VA_START && __STDC__
|
||||||
error (int status, int errnum, const char *message, ...)
|
error (int status, int errnum, const char *message, ...)
|
||||||
@ -139,37 +224,38 @@ error (status, errnum, message, va_alist)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
fflush (stdout);
|
fflush (stdout);
|
||||||
|
#ifdef _LIBC
|
||||||
|
flockfile (stderr);
|
||||||
|
#endif
|
||||||
if (error_print_progname)
|
if (error_print_progname)
|
||||||
(*error_print_progname) ();
|
(*error_print_progname) ();
|
||||||
else
|
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
|
#ifdef VA_START
|
||||||
VA_START (args, message);
|
VA_START (args, message);
|
||||||
# if HAVE_VPRINTF || _LIBC
|
error_tail (status, errnum, message, args);
|
||||||
vfprintf (stderr, message, args);
|
# ifdef _LIBC
|
||||||
# else
|
funlockfile (stderr);
|
||||||
_doprnt (message, args, stderr);
|
|
||||||
# endif
|
# endif
|
||||||
va_end (args);
|
|
||||||
#else
|
#else
|
||||||
fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
|
fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
|
||||||
#endif
|
|
||||||
|
|
||||||
++error_message_count;
|
++error_message_count;
|
||||||
if (errnum)
|
if (errnum)
|
||||||
{
|
fprintf (stderr, ": %s", strerror (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
|
|
||||||
}
|
|
||||||
putc ('\n', stderr);
|
putc ('\n', stderr);
|
||||||
fflush (stderr);
|
fflush (stderr);
|
||||||
if (status)
|
if (status)
|
||||||
exit (status);
|
exit (status);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sometimes we want to have at most one error per line. This
|
/* 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 const char *old_file_name;
|
||||||
static unsigned int old_line_number;
|
static unsigned int old_line_number;
|
||||||
|
|
||||||
if (old_line_number == line_number &&
|
if (old_line_number == line_number
|
||||||
(file_name == old_file_name || !strcmp (old_file_name, file_name)))
|
&& (file_name == old_file_name
|
||||||
|
|| strcmp (old_file_name, file_name) == 0))
|
||||||
/* Simply return and print nothing. */
|
/* Simply return and print nothing. */
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -209,40 +296,48 @@ error_at_line (status, errnum, file_name, line_number, message, va_alist)
|
|||||||
}
|
}
|
||||||
|
|
||||||
fflush (stdout);
|
fflush (stdout);
|
||||||
|
#ifdef _LIBC
|
||||||
|
flockfile (stderr);
|
||||||
|
#endif
|
||||||
if (error_print_progname)
|
if (error_print_progname)
|
||||||
(*error_print_progname) ();
|
(*error_print_progname) ();
|
||||||
else
|
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)
|
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
|
#ifdef VA_START
|
||||||
VA_START (args, message);
|
VA_START (args, message);
|
||||||
# if HAVE_VPRINTF || _LIBC
|
error_tail (status, errnum, message, args);
|
||||||
vfprintf (stderr, message, args);
|
# ifdef _LIBC
|
||||||
# else
|
funlockfile (stderr);
|
||||||
_doprnt (message, args, stderr);
|
|
||||||
# endif
|
# endif
|
||||||
va_end (args);
|
|
||||||
#else
|
#else
|
||||||
fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
|
fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
|
||||||
#endif
|
|
||||||
|
|
||||||
++error_message_count;
|
++error_message_count;
|
||||||
if (errnum)
|
if (errnum)
|
||||||
{
|
fprintf (stderr, ": %s", strerror (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
|
|
||||||
}
|
|
||||||
putc ('\n', stderr);
|
putc ('\n', stderr);
|
||||||
fflush (stderr);
|
fflush (stderr);
|
||||||
if (status)
|
if (status)
|
||||||
exit (status);
|
exit (status);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _LIBC
|
#ifdef _LIBC
|
||||||
|
@ -55,7 +55,7 @@ tests := tstscanf test_rdwr test-popen tstgetln test-fseek \
|
|||||||
tfformat tiformat tllformat tstdiomisc tst-printfsz tst-wc-printf \
|
tfformat tiformat tllformat tstdiomisc tst-printfsz tst-wc-printf \
|
||||||
scanf1 scanf2 scanf3 scanf4 scanf5 scanf7 scanf8 scanf9 scanf10 \
|
scanf1 scanf2 scanf3 scanf4 scanf5 scanf7 scanf8 scanf9 scanf10 \
|
||||||
scanf12 tst-tmpnam tst-cookie tst-obprintf tst-sscanf tst-swprintf \
|
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
|
test-srcs = tst-unbputc tst-printf
|
||||||
|
|
||||||
|
@ -19,13 +19,14 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
#include <wchar.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,
|
static void
|
||||||
a message describing the meaning of the contents of `errno' and a newline.
|
perror_internal (FILE *fp, const char *s)
|
||||||
If S is NULL or "", the colon and space are omitted. */
|
|
||||||
void
|
|
||||||
perror (const char *s)
|
|
||||||
{
|
{
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
int errnum = errno;
|
int errnum = errno;
|
||||||
@ -40,9 +41,47 @@ perror (const char *s)
|
|||||||
errstring = __strerror_r (errnum, buf, sizeof buf);
|
errstring = __strerror_r (errnum, buf, sizeof buf);
|
||||||
|
|
||||||
#ifdef USE_IN_LIBIO
|
#ifdef USE_IN_LIBIO
|
||||||
if (_IO_fwide (stderr, 0) > 0)
|
if (_IO_fwide (fp, 0) > 0)
|
||||||
(void) fwprintf (stderr, L"%s%s%s\n", s, colon, errstring);
|
(void) fwprintf (fp, L"%s%s%s\n", s, colon, errstring);
|
||||||
else
|
else
|
||||||
#endif
|
#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