mirror of
https://sourceware.org/git/glibc.git
synced 2025-08-07 06:43:00 +03: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:
@@ -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;
|
||||
}
|
Reference in New Issue
Block a user