Named Pipe unformatted I/O (PR30162)

Jerry DeLisle jvdelisle@verizon.net
Mon Jan 1 21:04:00 GMT 2007


Thomas Koenig wrote:
> Hi Jerry,
> 
>> For ACCESS="direct" and ACCESS="stream" with POS= I plan to test for named 
>> pipes and issue an error.
> 
> It's probably better to check for a seekable file in this case
> (using a sanitized way to check for is_seekable).  This would
> also cover standard input/output to a terminal, regular file or pipe.

I agree.

> 
>> As you may know, FORM="unformatted" is much trickier.  I have a couple of 
>> ideas:
>>
>> Keep in mind that right now for a write statement such as:
>>
>> WRITE(10) var1, var2, var3
>>
>> The record size is sizeof(var1) + sizeof(var2) + sizeof(var3)
>>
>> we build a set of calls to the library like this:
>>
>> st_write
>> transfer var1
>> transfer var2
>> transfer var3
>> st_write_done
>>
>> Record size is currently determined by accumulating the iolengths as we go, 
>> forcing us to seek back in the file and fill in the starting record marker.
>>
>> Idea 1) We could modify the frontend to include a call to test for named 
>> pipes and setup the calls to run through the transfers between st_write and 
>> st_write_done with two passes.  At run time, if the file is not a named 
>> pipe, we skip the first pass, otherwise we proceed with the first pass 
>> similar to INQUIRE with IOLENGTH= and we determine the record size. The 
>> second pass then uses the record size determined to just do the transfers 
>> without any seeking back to fill in the starting record number.
> 
> Unfortunately, this approach will cause problems for allocatable
> functions.  Consider
> 
> program main
>   print *,foo(1)
> contains
>   function foo (n) result(res)
>     integer, intent(in) :: n
>     integer, allocatable :: res(:)
>     logical :: init = .false.;
> 
>     if (.not. init) then
>        allocate (res(1))
>        init = .true.
>     else
>        allocate (res(2))
>     end if
> 
>     res = n
>   end function foo
> end program main
> 
> (which is legal, if a bit strange).
> 
> Calling foo twice on output for a named pipe would be strange
> indeed.  Also, functions can be computationally intensive.

I thought about this problem.  Its the other half of tricky.  We have to be 
smart enough to call the function once and compute the result along with getting 
the record size and saving the result for the actual transfer.
> 
>> Idea 2) In the frontend, actually build a linked list of the READ or WRITE 
>> output list that would allow easy scanning through the list to compute the 
>> record size.  Obviously, the output list is in the frontend already (in 
>> some form), so maybe all we do is pass that list to the library for a 
>> special call to a new function "get_record_length" and then use that record 
>> length.  This approach would clean up some of the bean counting going on in 
>> the transfer routines now.  The library could also go through the list and 
>> decide which transfer calls to make or leave it as is in the frontend to 
>> save runtime overhead.
> 
> I see the same problem with allocatable functions - do we call them
> once or twice?
> 

Once and transfer the result as I mentioned above.  My thought is to have a 
field in the output list which is a pointer to the result of the function calls. 
  Or something similar.

>> Other suggestions?  (I am leaning toward 2)
> 
> For non-seekable files, we will probably have to revert to
> buffering.  We can limit the length of the buffer by using
> subrecords.

I think we can do this effectively with pointers since the function results have 
to be computed somewhere and saved somewhere regardless.  In other words, the 
results are their own buffers.
> 
> What I tried to do, but didn't succeed, was to change the general
> buffering scheme so that lseeks were ignored if they fell outside
> the current buffer.  This worked, but led to regressions in
> backspace.

No question this is going to be difficult to sort out, but conceptually I think 
we can do it.

> 
> 	Thomas
> 



More information about the Fortran mailing list