X-Authentication-Warning: delorie.com: mail set sender to djgpp-workers-bounces using -f X-Recipient: djgpp-workers AT delorie DOT com X-Authenticated: #27081556 X-Provags-ID: V01U2FsdGVkX1+HeClKmDuHrCxpUIXzprQ5cUZ8v+uLrVGHidENTl Zk1F/1SsEDfgiZ From: Juan Manuel Guerrero To: djgpp-workers AT delorie DOT com Subject: NULL pointer support for freopen Date: Sun, 6 May 2012 18:06:08 +0200 User-Agent: KMail/1.9.10 MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline Message-Id: <201205061806.08510.juan.guerrero@gmx.de> X-Y-GMX-Trusted: 0 Reply-To: djgpp-workers AT delorie DOT com I have tried to implement the case when a NULL pointer is passed as filename. Because DOS does not allow to change file descriptor flags of open files, only the change of textmode using setmode() is supported. Any other function call with a NULL pointer as filename argument will fail with EBADF. Please note that a different file acces mode will make the call fail, e.g.: if the new mode is O_WRONLY but the old mode was O_RDWR then the call will fail. No file access mode is allowed. Suggestions, objections, comments are welcome. Regards, Juan M. Guerrero diff -aprNU5 djgpp.orig/src/docs/kb/wc204.txi djgpp/src/docs/kb/wc204.txi --- djgpp.orig/src/docs/kb/wc204.txi 2012-01-22 23:40:28 +0000 +++ djgpp/src/docs/kb/wc204.txi 2012-05-06 14:57:30 +0000 @@ -1244,5 +1244,9 @@ the modul with @code{libc.a} to resolve @findex STYP_NRELOC_OVFL AT r{, new flag bit added to @code{s_flags} of @acronym{COFF} section header} The @code{s_flags} of the @acronym{COFF} section header now honors the new @code{STYP_NRELOC_OVFL} bit that signals that the section contains extended relocations and that the @code{s_nreloc} counter has overflown. The bit set in case of overflow by @code{STYP_NRELOC_OVFL} is @code{0x01000000}. +@findex freopen AT r{, and support of @code{NULL} pointer as @var{filename} argument} +@code{freopen} now accepts a @code{NULL} pointer as first argument. In this +case the textmode of the file associated to the third argument is changed according +to the the second argument. diff -aprNU5 djgpp.orig/src/libc/ansi/stdio/freopen.c djgpp/src/libc/ansi/stdio/freopen.c --- djgpp.orig/src/libc/ansi/stdio/freopen.c 2012-05-06 13:30:26 +0000 +++ djgpp/src/libc/ansi/stdio/freopen.c 2012-05-06 16:57:16 +0000 @@ -1,5 +1,6 @@ +/* Copyright (C) 2012 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 2002 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 2001 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1999 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */ @@ -10,25 +11,23 @@ #include #include #include #include #include +#include FILE * freopen(const char *file, const char *mode, FILE *f) { int fd, fdo, rw, oflags = 0; char tbchar; - if (file == NULL || mode == NULL || f == NULL) + if (mode == NULL || f == NULL) return NULL; rw = (mode[1] == '+') || (mode[1] && (mode[2] == '+')); - fdo = fileno(f); - fclose(f); - switch (*mode) { case 'a': oflags = O_CREAT | (rw ? O_RDWR : O_WRONLY) | O_APPEND; break; @@ -50,11 +49,40 @@ freopen(const char *file, const char *mo else if (tbchar == 'b') oflags |= O_BINARY; else oflags |= (_fmode & (O_TEXT | O_BINARY)); - fd = open(file, oflags, 0666); + fdo = fileno(f); + if (fd = fdo, file) + { + fclose(f); + fd = open(file, oflags, 0666); + } + else + { + /* If file is NULL, the file should not be closed but reused. + DOS does not allow to change descriptor flags of open files. + Only O_BINARY and O_TEXT flag changes are supported. */ + int oldflags = fcntl(fdo, F_GETFL); + if (oldflags == -1 || ((oflags & O_ACCMODE) != (oldflags & O_ACCMODE))) + { + errno = EBADF; + fd = -1; + } + else if (!(oflags & _fmode & (O_BINARY ^ O_TEXT))) + { + if (fflush(f) == -1 || (tbchar != 'b' && tbchar != 't') + || (setmode(fdo, tbchar == 'b' ? O_BINARY : O_TEXT) == -1)) + { + errno = EBADF; + fd = -1; + } + else + fd = fdo; + } + } + if (fd < 0) return NULL; if (fd != fdo && fdo >= 0) { diff -aprNU5 djgpp.orig/src/libc/ansi/stdio/freopen.txh djgpp/src/libc/ansi/stdio/freopen.txh --- djgpp.orig/src/libc/ansi/stdio/freopen.txh 2003-03-26 19:47:36 +0000 +++ djgpp/src/libc/ansi/stdio/freopen.txh 2012-05-06 16:09:22 +0000 @@ -14,19 +14,31 @@ This function closes @var{file} if it wa file like @code{fopen(filename, mode)} (@pxref{fopen}) but it reuses @var{file}. This is useful to, for example, associate @code{stdout} with a new file. +If @var{filename} is a @code{NULL} pointer, the function will attempt to change +the mode of @var{file} to that specified by @var{mode}. In this case, the file +descriptor associated with @var{file} need not be closed if the call to @var{freopen} +succeeds. +This fails in all but one case, and sets @code{errno} to @code{EBADF}, since DOS +and Windows do not allow changing the descriptor flags after the file is open. +The one allowed case is for @code{O_BINARY} and @code{O_TEXT}. That is, calls +that @strong{only} change the file textmode will succeed and all others will +fail. + @subheading Return Value -The new file, or @code{NULL} on error. +The new file, or @code{NULL} on error and @code{errno} is set. @subheading Portability @portability ansi, posix @subheading Example @example freopen("/tmp/stdout.dat", "wb", stdout); + +freopen(NULL, "rb", stdin); /* Change stdin to O_BINARY mode. */ @end example