diff mbox

[libfortran] PR44931 For INPUT_UNIT, INQUIRE NAME= should not return "stdin"

Message ID 4C4B8BA3.2070202@verizon.net
State New
Headers show

Commit Message

Jerry DeLisle July 25, 2010, 12:56 a.m. UTC
Hi Folks,

The attach patch uses ttyname to return the device file name for inquire by unit.

Regression tested on x86-64.

Test case attached, but the reulst are system dependent so I will not add it to 
the testsuite.

OK for trunk?

Regards,

Jerry

2010-07-24  Jerry DeLisle  <jvdelisle@gcc.gnu.org>

	PR libfortran/44931
	* io/inquire.c (inquire_via_unit): Use ttyname to return actual device
	file name for stdin, stdout, and stderr.  If ttyname does not succeed
	fall back to default names for these units. Include string.h to allow
	using strlen function.
	* unix.c: Remove typedef of unix_stream structure, move to unix.h.
	* unix.h: Add typedef of unix_stream structure so that it is
	accessible to inquire.c.


program test_inquire
   character(80) :: str1
   open(10, file="myfilename")
   str1 = ""
   inquire(unit=6, name=str1)
   print *, 1,str1
   str1 = ""
   inquire(unit=5, name=str1)
   print *, 2,str1
   str1 = ""
   inquire(unit=37, name=str1)
   print *, 3,str1
   str1 = ""  ! Empty string since no connection has been made to unit 37
   inquire(unit=10, name=str1)
   print *, 4,str1
   open(6,file="test.dat")
   inquire(6,name=str1)
   if (str1 /= "test.dat") call abort()
   open(6,file="/dev/pts/2")
   print *, 5,str1
end program test_inquire

Comments

Tobias Burnus July 25, 2010, 9 a.m. UTC | #1
Dear Jerry, Dave, and Kai,

Dave and Kai: I have CCed you as I have a question regarding MinGW/Cygwin.

Jerry DeLisle wrote:
> The attach patch uses ttyname to return the device file name for
> inquire by unit.
> Regression tested on x86-64.
>
> Test case attached, but the reulst are system dependent so I will not
> add it to the testsuite.

Kai, Dave: The idea is that INQUIRE returns for stdin, stdout, and
stderr a "filename", which can be used to '(re)open' ([re]associate) a
Fortran I/O unit number with those standard I/O "streams". (Non
normative note in the standard: "the value [for NAME=] returned [by
"INQUIRE(UNIT=...,NAME=...)"] shall be suitable for use as the value of
the file-name-expr in the FILE= specifier in an OPEN statement.")

Under Unix, ttynam should roughly do this, but I fear it might not work
under Windows - in particular under MinGW(.org,64). Or does it?

Would it be an option to use conout$, conin$ and conerr$ for those? I
think on MinGW, libgfortran (io/unix.c) uses them directly (well conerr$
= conout$) while on cygwin those are mapped to /dev/con{in,out,err}. At
least for MinGW this seems to be required as Windows does not seem to
have a tty concept. For Cygwin the Unix approach should work.

> OK for trunk?

I think you need to guard the use of ttyname by

#ifdef HAVE_TTYNAME
...
#else
 ...
#endif

Besides, I wonder whether using "" as string is better than using the
default std{in,out,err} in case ttyname fails. (This happens for
instance if the standard I/O redirected to a file or pipe.)

Otherwise, the patch looks fine to me.

Tobias

> 2010-07-24  Jerry DeLisle  <jvdelisle@gcc.gnu.org>
>
>     PR libfortran/44931
>     * io/inquire.c (inquire_via_unit): Use ttyname to return actual
> device
>     file name for stdin, stdout, and stderr.  If ttyname does not succeed
>     fall back to default names for these units. Include string.h to allow
>     using strlen function.
>     * unix.c: Remove typedef of unix_stream structure, move to unix.h.
>     * unix.h: Add typedef of unix_stream structure so that it is
>     accessible to inquire.c.
Thomas Koenig July 25, 2010, 9:19 a.m. UTC | #2
Tobias Burnus wrote:

> Besides, I wonder whether using "" as string is better than using the
> default std{in,out,err} in case ttyname fails. (This happens for
> instance if the standard I/O redirected to a file or pipe.) 

For Linux, we could return /proc/self/fd/1 for standard output (0 and 2
correspondingly).  This appears to work, as this little program shows:

program main
  implicit none
  open(unit=10,file='/proc/self/fd/1')
  write (10,*) 'Hello, world!'
end program main

	Thomas
Tobias Burnus July 25, 2010, 9:39 a.m. UTC | #3
Thomas Koenig wrote:
> Tobias Burnus wrote
>> Besides, I wonder whether using "" as string is better than using the
>> default std{in,out,err} in case ttyname fails. (This happens for
>> instance if the standard I/O redirected to a file or pipe.) 
>>     
> For Linux, we could return /proc/self/fd/1 for standard output (0 and 2
> correspondingly).  This appears to work, as this little program shows:
>   

Well, I think using /dev/std{in,out,err} is more portable than
/proc/self/fd/{0,1,2}. However, the question is whether those device
files are just common or truly ubiquitous on non-Windows GCC platforms;
I fear they are just common. I have checked the File Hierarchy Standard
it it does not specify anything under /dev/*. One could (on non-Windows)
of course check the existence of "/dev/std*" and if it does not exist
fall back to ttypname and if it also fails (or HAS_TTYNAME is not
defined) fall back to "". But the question is whether one should do so
much effort - most of the time one simply uses the units without
INQUIREing the filename - to (re)open the standard I/O streams.

(Side note: The 0,1,2 numbers are defined in POSIX; they are the values
of the unistd.h's symbolic constants STD{IN,OUT,ERR}_FILENO.)

Tobias
Iain Sandoe July 25, 2010, 10:18 a.m. UTC | #4
On 25 Jul 2010, at 10:39, Tobias Burnus wrote:

> Thomas Koenig wrote:
>> Tobias Burnus wrote
>>> Besides, I wonder whether using "" as string is better than using  
>>> the
>>> default std{in,out,err} in case ttyname fails. (This happens for
>>> instance if the standard I/O redirected to a file or pipe.)
>>>
>> For Linux, we could return /proc/self/fd/1 for standard output (0  
>> and 2
>> correspondingly).  This appears to work, as this little program  
>> shows:
>>
>
> Well, I think using /dev/std{in,out,err} is more portable than
> /proc/self/fd/{0,1,2}.

FWIW:

/dev/std{in,out,err} exist on Darwin

/proc does not.

cheers,
Iain
Jerry DeLisle July 25, 2010, 3:31 p.m. UTC | #5
On 07/25/2010 02:00 AM, Tobias Burnus wrote:
> Dear Jerry, Dave, and Kai,
>
> Dave and Kai: I have CCed you as I have a question regarding MinGW/Cygwin.
>
> Jerry DeLisle wrote:
>> The attach patch uses ttyname to return the device file name for
>> inquire by unit.
>> Regression tested on x86-64.
>>
>> Test case attached, but the results are system dependent so I will not
>> add it to the testsuite.
>
> Kai, Dave: The idea is that INQUIRE returns for stdin, stdout, and
> stderr a "filename", which can be used to '(re)open' ([re]associate) a
> Fortran I/O unit number with those standard I/O "streams". (Non
> normative note in the standard: "the value [for NAME=] returned [by
> "INQUIRE(UNIT=...,NAME=...)"] shall be suitable for use as the value of
> the file-name-expr in the FILE= specifier in an OPEN statement.")
>
> Under Unix, ttynam should roughly do this, but I fear it might not work
> under Windows - in particular under MinGW(.org,64). Or does it?

ttynam is supported under Cygwin according to their documentation.  I will test it.

Regarding mingw-32/64 I will defer to Kai, but it looks like they do from googling.

>
> Would it be an option to use conout$, conin$ and conerr$ for those? I
> think on MinGW, libgfortran (io/unix.c) uses them directly (well conerr$
> = conout$) while on cygwin those are mapped to /dev/con{in,out,err}. At
> least for MinGW this seems to be required as Windows does not seem to
> have a tty concept. For Cygwin the Unix approach should work.
>
>> OK for trunk?
>
> I think you need to guard the use of ttyname by
>
> #ifdef HAVE_TTYNAME
> ...
> #else
>   ...
> #endif
>
> Besides, I wonder whether using "" as string is better than using the
> default std{in,out,err} in case ttyname fails. (This happens for
> instance if the standard I/O redirected to a file or pipe.)
>
> Otherwise, the patch looks fine to me.

I have guarded it with HAVE_TTYNAME and if not defined we fall back to current 
gfortran behavior which almost everyone is happy with. I have tested that it 
works.  To me this is the safest way to go initially with this.

OK to commit?

Jerry
Dave Korn July 27, 2010, midnight UTC | #6
On 25/07/2010 16:31, Jerry DeLisle wrote:
> On 07/25/2010 02:00 AM, Tobias Burnus wrote:
>> Dear Jerry, Dave, and Kai,
>>
>> Dave and Kai: I have CCed you as I have a question regarding
>> MinGW/Cygwin.

  Forgot to actually Cc us!

>> Jerry DeLisle wrote:
>>> The attach patch uses ttyname to return the device file name for
>>> inquire by unit.
>>> Regression tested on x86-64.
>>>
>>> Test case attached, but the results are system dependent so I will not
>>> add it to the testsuite.
>>
>> Kai, Dave: The idea is that INQUIRE returns for stdin, stdout, and
>> stderr a "filename", which can be used to '(re)open' ([re]associate) a
>> Fortran I/O unit number with those standard I/O "streams". (Non
>> normative note in the standard: "the value [for NAME=] returned [by
>> "INQUIRE(UNIT=...,NAME=...)"] shall be suitable for use as the value of
>> the file-name-expr in the FILE= specifier in an OPEN statement.")
>>
>> Under Unix, ttynam should roughly do this, but I fear it might not work
>> under Windows - in particular under MinGW(.org,64). Or does it?
> 
> ttynam is supported under Cygwin according to their documentation.  I
> will test it.

  I gave it a quick check, it works, returns "/dev/console" or "/dev/ttyN"
depending if you're running in a DOS box or a graphical shell.

> Regarding mingw-32/64 I will defer to Kai, but it looks like they do
> from googling.

  Kai Cc'd in.  Kai, thread begins at:

	http://gcc.gnu.org/ml/gcc-patches/2010-07/threads.html#01977

>> Would it be an option to use conout$, conin$ and conerr$ for those? I
>> think on MinGW, libgfortran (io/unix.c) uses them directly (well conerr$
>> = conout$) 

  That's how I understand it as well, so it makes a ton of sense to me if
those names get used here as well.

>> while on cygwin those are mapped to /dev/con{in,out,err}. At
>> least for MinGW this seems to be required as Windows does not seem to
>> have a tty concept. For Cygwin the Unix approach should work.

  And if it doesn't, we'll fix it in Cygwin for you :)

    cheers,
      DaveK
H.J. Lu July 29, 2010, 2:21 p.m. UTC | #7
On Sat, Jul 24, 2010 at 5:56 PM, Jerry DeLisle <jvdelisle@verizon.net> wrote:
> Hi Folks,
>
> The attach patch uses ttyname to return the device file name for inquire by
> unit.
>
> Regression tested on x86-64.
>
> Test case attached, but the reulst are system dependent so I will not add it
> to the testsuite.
>
> OK for trunk?
>
> Regards,
>
> Jerry
>
> 2010-07-24  Jerry DeLisle  <jvdelisle@gcc.gnu.org>
>
>        PR libfortran/44931
>        * io/inquire.c (inquire_via_unit): Use ttyname to return actual
> device
>        file name for stdin, stdout, and stderr.  If ttyname does not succeed
>        fall back to default names for these units. Include string.h to allow
>        using strlen function.
>        * unix.c: Remove typedef of unix_stream structure, move to unix.h.
>        * unix.h: Add typedef of unix_stream structure so that it is
>        accessible to inquire.c.
>
>

This caused:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=45131
diff mbox

Patch

Index: inquire.c
===================================================================
--- inquire.c	(revision 162497)
+++ inquire.c	(working copy)
@@ -26,6 +26,7 @@  see the files COPYING3 and COPYING.RUNTIME respect
 
 /* Implement the non-IOLENGTH variant of the INQUIRY statement */
 
+#include <string.h>
 #include "io.h"
 #include "unix.h"
 
@@ -66,7 +67,23 @@  inquire_via_unit (st_parameter_inquire *iqp, gfc_u
 
   if ((cf & IOPARM_INQUIRE_HAS_NAME) != 0
       && u != NULL && u->flags.status != STATUS_SCRATCH)
-    fstrcpy (iqp->name, iqp->name_len, u->file, u->file_len);
+    {
+      if (u->unit_number == options.stdin_unit
+	  || u->unit_number == options.stdout_unit
+	  || u->unit_number == options.stderr_unit)
+	{
+	  char * tmp = ttyname (((unix_stream *) u->s)->fd);
+	  if (tmp != NULL)
+	    {
+	      int tmplen = strlen (tmp);
+	      fstrcpy (iqp->name, iqp->name_len, tmp, tmplen);
+	    }
+	  else /* If ttyname does not work, go with the default.  */
+	    fstrcpy (iqp->name, iqp->name_len, u->file, u->file_len);
+	}
+      else
+	fstrcpy (iqp->name, iqp->name_len, u->file, u->file_len);
+    }
 
   if ((cf & IOPARM_INQUIRE_HAS_ACCESS) != 0)
     {
Index: unix.c
===================================================================
--- unix.c	(revision 162497)
+++ unix.c	(working copy)
@@ -135,28 +135,6 @@  typedef struct stat gfstat_t;
 
 static const int BUFFER_SIZE = 8192;
 
-typedef struct
-{
-  stream st;
-
-  gfc_offset buffer_offset;	/* File offset of the start of the buffer */
-  gfc_offset physical_offset;	/* Current physical file offset */
-  gfc_offset logical_offset;	/* Current logical file offset */
-  gfc_offset file_length;	/* Length of the file, -1 if not seekable. */
-
-  char *buffer;                 /* Pointer to the buffer.  */
-  int fd;                       /* The POSIX file descriptor.  */
-
-  int active;			/* Length of valid bytes in the buffer */
-
-  int prot;
-  int ndirty;			/* Dirty bytes starting at buffer_offset */
-
-  int special_file;		/* =1 if the fd refers to a special file */
-}
-unix_stream;
-
-
 /* fix_fd()-- Given a file descriptor, make sure it is not one of the
  * standard descriptors, returning a non-standard descriptor.  If the
  * user specifies that system errors should go to standard output,
Index: unix.h
===================================================================
--- unix.h	(revision 162497)
+++ unix.h	(working copy)
@@ -41,6 +41,29 @@  struct stream
   int (*close) (struct stream *);
 };
 
+
+typedef struct
+{
+  stream st;
+
+  gfc_offset buffer_offset;	/* File offset of the start of the buffer */
+  gfc_offset physical_offset;	/* Current physical file offset */
+  gfc_offset logical_offset;	/* Current logical file offset */
+  gfc_offset file_length;	/* Length of the file, -1 if not seekable. */
+
+  char *buffer;                 /* Pointer to the buffer.  */
+  int fd;                       /* The POSIX file descriptor.  */
+
+  int active;			/* Length of valid bytes in the buffer */
+
+  int prot;
+  int ndirty;			/* Dirty bytes starting at buffer_offset */
+
+  int special_file;		/* =1 if the fd refers to a special file */
+}
+unix_stream;
+
+
 /* Inline functions for doing file I/O given a stream.  */
 static inline ssize_t
 sread (stream * s, void * buf, ssize_t nbyte)