David Vowles writes:
> Although your library carefully assigns unit numbers
> there is no way of ensuring that the end-user does not try to open a
> unit that your library code has already opened.
Yes, that's a fundamental problem of such schemes. Any of several
schemes can work fine if all the code in a program is consistent
about using them. But random code from other sources isn't likely
to use the same scheme as whatever you come up with.
> To minimize the risk of
> clashes in this situation I reserve unit numbers with high values (e.g.
> 1,000,000 to 1,000,999).
That doesn't seem likely to be particularly good about portability.
Lots of implementations don't accept unit numbers greater than 99.
Perhaps the newest versions of current compilers might be better about
this, but I'm sure there are still many compilers in use with
limitations like that. (The question still seems to come up on
occasion from users who have found that some code won't work because
it used large unit numbers).
Though as long as you define this range in one easy-to-change place
and document it is a system dependency, it could presumably be
tailored to accomodate systems with low limits on unit numbers.
My hack for dealing with the problem of code that doesn't use my
assign_lun procedure is to provide a separate procedure reserve_lun.
If I know that some library I'm using hard-wires 42 as a lun, I can
tnen do "call reserve_lun(42)", which will keep assign_lun from using
that one. I can also just call reserve_lun in a loop to reserve a
range of luns.
This does assume that I can find out a'priori what particular luns the
library uses (or at least a range in which they will lie). This is
only an issue for luns that the library might try to use at some
future time. Like several of the other variants of this kind of
capability, I notice and avoid luns that are currently open when
I invoke assign_lun.
This isn't a perfect solution, but its the one I use.
Below is my version of this capability. Extracted from a file that
also contained several other utility functions of the nature indicated
by the module name. I think the only thing this references that I
didn't include is my error_halt subroutine, whose function should
be obvious from the name and usage.
This code isn't very sophisticated. I've seen other versions that
do some additional checks of the unit number. (I think it was to
make sure that the unit existed). Strictly speaking those might be
needed, and someday I might add them...but this code was written
before that was pointed out to me....and I've never actually run into
a problem from that, so I left the code as is.
!-- sysdepIo.f90
!-- System-dependent. Generic version.
!-- 9 Dec 92, Richard Maine: Version 1.0.
!....elided a bunch of stuff....this copy just has the lun assignments,
module sysdep_io
!-- General system-dependent support routines.
!-- System-dependent. Generic version.
!-- 20 Jun 96, Richard Maine.
implicit none
private
!-- The list of legal logical unit numbers is system-dependent.
!-- We avoid low-numbered luns to minimize likely system conflicts.
integer, parameter :: min_lun=10, max_lun=99
logical, save :: lun_is_free(min_lun:max_lun) = .true.
!-- Public procedures.
public assign_lun, release_lun, reserve_lun
contains
subroutine assign_lun (lun)
!-- Assign an available Fortran logical unit number.
!-- Aborts if no lun can be assigned; there are no error returns.
!-- 15 Jun 90, Richard Maine.
!-------------------- interface.
integer, intent(out) :: lun !-- Logical unit number.
!-------------------- local.
integer :: iostat
logical :: used
!-------------------- executable code.
do lun = min_lun , max_lun
if (lun_is_free(lun)) then
inquire(unit=lun, opened=used, iostat=iostat)
if (iostat /= 0) used = .true.
lun_is_free(lun) = .false.
if (.not.used) return
end if
end do
call error_halt('No luns available in assign_lun')
return
end subroutine assign_lun
subroutine reserve_lun (lun)
!-- Reserve a specific Fortran logical unit number.
!-- 15 Jun 90, Richard Maine.
!-------------------- interface.
integer, intent(in) :: lun
!-- Logical unit number. Illegal values are quietly ignored.
!-------------------- executable code.
if (lun>=min_lun .and. lun<=max_lun) lun_is_free(lun) = .false.
return
end subroutine reserve_lun
subroutine release_lun (lun)
!-- Release a Fortran logical unit number for reuse.
!-- No checking is done to see that the lun is actually closed;
!-- assign_lun will check that before re-assigning it.
!-- 15 Jun 90, Richard Maine.
!-------------------- interface.
integer, intent(in) :: lun
!-- Logical unit number. Illegal values are quietly ignored.
!-------------------- executable code.
if (lun>=min_lun .and. lun<=max_lun) lun_is_free(lun) = .true.
end subroutine release_lun
end module sysdep_io
--
Richard Maine | Good judgment comes from experience;
[log in to unmask] | experience comes from bad judgment.
| -- Mark Twain
|