I'd like to read in some text strings from the command line used to run a program. I'm using the internal subroutine GET_COMMAND_ARGUMENT
in a program that basically is something like:
program test
character(len=100) :: argument
call GET_COMMAND_ARGUMENT(1,argument)
print*, argument
end program test
The issue here is that I feel it's a bit dangerous to set the maximum length of the string at compilation time. Some of the arguments are typically files with their path, so they might be very long. A solution involving setting the length statically to 1000 sounds like an ugly workaround.
Isn't there a more elegant way in Fortran to define a string able to contain a chain of characters whose length is only known at run time?
It is possible to use what are called deferred-length character variables. These are not of a fixed constant length and their use can be found in questions such as a related one about data input.
However, even with a deferred length variable used like (for this is the syntax)
character(len=:), allocatable :: argument
allocate(character(some_length) :: argument) ! For integer some_length
call GET_COMMAND_ARGUMENT(1,argument)
print*, argument
end
one still has to worry about what some_length
should be. If we just choose 100, we're back to where we were.
We have to worry about this because get_command_argument
doesn't take such a deferred length argument and allocate it to the desired length. That is
character(len=:), allocatable :: argument
call GET_COMMAND_ARGUMENT(1,argument) ! Will argument be allocated in the subroutine?
print*, argument
end
offers the answer "no".
Coming, then, to a way to handle this, we look at other (optional) arguments to get_command_argument
. In particular, there is one called length
:
character(len=:), allocatable :: argument
integer arglen
call GET_COMMAND_ARGUMENT(1,length=arglen)
allocate(character(arglen) :: argument)
call GET_COMMAND_ARGUMENT(1,value=argument)
print*, argument
end
Naturally, one could create a wrapper subroutine which did take an allocatable deferred length character variable and did all that work.
I will leave this for completeness, it may be useful to somebody, but francescalus' answer is much better.
Basically, just read it with some default length, check the STATUS
variable and if it did not fit, try again.
From the gcc manual:
If the argument retrieval fails, STATUS is a positive number; if VALUE contains a truncated command line argument, STATUS is -1; and otherwise the STATUS is zero.
So:
character(len=:), allocatable :: argument
integer :: stat, n
n = 100
allocate(character(n) :: argument)
do
call GET_COMMAND_ARGUMENT(1,argument, status=stat)
if (stat>=0) exit
deallocate(argument)
n = n * 2
allocate(character(n) :: argument)
end do
if (stat>0) error...
argument = trim(argument)
print*, argument
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With