getarg


paus
08-25-2008, 08:22 AM
Hello,

I want to use getarg to define a global variable in a module (afterwards I want to execute this fortran compiled program using as second argument a number (integer)). I tried:

MODULE global_vars
CHARACTER(len=3) :: BUFFER
INTEGER :: ntimes

contains
CALL getarg(2,BUFFER)
READ(BUFFER,*) ntimes

END MODULE global_vars

but this fails given a message:

fortcom: Error: /dirX/program.f90, line 66: The statement following a CONTAINS is not a function-stmt or a subroutine-stmt.
CALL getarg(2,BUFFER)

why is this the case, and how to bypass this?

Thanks for any help.

davekw7x
08-25-2008, 03:12 PM
I want to use getarg to define a global variable in a module...

fortcom: Error: /dirX/program.f90, line 66: The statement following a CONTAINS is not a function-stmt or a subroutine-stmt.
CALL getarg(2,BUFFER)
.

Modules can contain variables and functions and subroutines, not just any old code. How would your main program invoke that code unless the code appeared in a subroutine or function that was contained in the module?

I'm not sure what you have in mind (getarg() is a built-in function; it doesn't define anything), but here's something to try. It works for me with GNU gfortran (Version 4.1.2)

MODULE global_vars
CHARACTER(len=3) :: buffer
INTEGER :: ntimes
END MODULE global_vars

PROGRAM test_globals
USE global_vars

write(*, '("Number of arguments = ",I0)') iargc()
if (iargc() .lt. 2) goto 998

call getarg(2,buffer)
read(buffer,*, ERR=999) ntimes
write(*,'("ntimes = ", I0)') ntimes
stop

998 print *,"Insufficient input."
stop
999 print *,"Bad input."

END PROGRAM test_globals


Here are a few runs:


$./test_globals
Number of arguments = 0
Insufficient input.



$./test_globals 111111 222222 333333
Number of arguments = 3
ntimes = 222



$./test_globals 11z 22 333
Number of arguments = 3
ntimes = 22



$./test_globals 11 22.2 33
Number of arguments = 3
Bad input.


Regards,

Dave

paus
08-26-2008, 05:22 AM
The main idea is to use a script that feeds a variable through execution of this fortran executable, something like:

execute fortran_file arg1 arg2

where arg1=filename
and arg2=ntimes (a number)

I want to define ntimes in a general way, so everywhere in the program it can be used. I thought making a module would be a neat way, but I guess this is harder as I thought.

I can do it in the way you suggested, but since I also use ntimes in subroutines, it would be more practical to create a global variable ... otherwise I would have to CALL getarg in all subroutines as well.

Any suggestion would be great.

Thanks.
Tim

davekw7x
08-26-2008, 10:01 AM
... it would be more practical to create a global variable ...
Any suggestion would be great.

The traditional way to make global variables in Fortran (when it was spelled FORTRAN, and didn't have numbers like II, IV, 77, 90, etc.) was to use common blocks. Use of named blocks could make selectively "global" variables that were available in any subprogram that used that named block.

Use of a module can make variables that are "somewhat global" in a way similar to the methodology of using common blocks. That is, the variables are available to any subprograms that use that module. So you could have a function or subroutine (that uses that module) read in the variables and go from there.

Modules can also contain subprograms that will be available to any other part of the program that uses that module. By compiling modules separately, they can be linked with other parts of programs under development without having to recompile the module each time.

Whether you use common blocks of modules to give you "global" variables, I offer the following opinion:



Gratuitous use of global variables, in general is frowned on (by many programmers and analysts) in modern times.
Here's the drill:
Pass variables to subprograms as parameters.
Declare everything explicitly in each part of the program.

Among other things, this makes debugging more straightforward, since it decreases the likelihood that simple typos (misspelling variable names in subprograms, for example) can cause disastrous side effects.


It's just an opinion. Some still cling to the mid-20th-century notion (when mainframes had a few tens of thousands of words of memory and CPU instruction cycle times were measured in microseconds) that using globals is, somehow, more "efficient" than passing parameters.

For an example without globals:


FUNCTION getinputs(iname, inumber)
IMPLICIT NONE
INTEGER :: getinputs
CHARACTER(LEN=10):: iname
INTEGER :: inumber
CHARACTER(LEN=10):: buffer

IF (iargc() .LT. 2) GOTO 998

CALL getarg(1,iname)
WRITE(*,'("getinputs: file name is ",A)') iname

CALL getarg(2,buffer)
READ(buffer,*, ERR=999) inumber
WRITE(*,'(" iterations = ", I3)') inumber
getinputs = 1
RETURN

998 WRITE(*, '(/"Insufficient input."/)')
getinputs = 0
RETURN

999 WRITE(*, '(/"Bad input."/)')
getinputs = 0
RETURN
END FUNCTION getinputs


SUBROUTINE f1(fnam, fnum)
IMPLICIT NONE
CHARACTER(LEN=10):: fnam
INTEGER :: fnum
WRITE(*,'("f1: fnam = ",A, ", fnum = ", I3)') fnam,fnum
END SUBROUTINE

SUBROUTINE f2(fname, fnumber)
IMPLICIT NONE
CHARACTER(LEN=10):: fname
INTEGER :: fnumber
WRITE(*,'("f2: fname = ",A, ", fnumber = ", I3)') fname,fnumber
END SUBROUTINE

PROGRAM test_args
IMPLICIT NONE

INTEGER :: getinputs

CHARACTER(LEN=10):: filename
INTEGER :: iterations

IF (getinputs(filename, iterations) .NE. 0) THEN
CALL f1(filename,iterations)
CALL f2(filename,iterations)
END IF
STOP


END PROGRAM test_args



Here's a run (as compiled with either GNU g77 or GNU gfortran)

$./test_args data.txt 4
getinputs: file name is data.txt
iterations = 4
f1: fnam = data.txt , fnum = 4
f2: fname = data.txt , fnumber = 4


Here's another:

$./test_args data.txt 4z
getinputs: file name is data.txt

Bad input.




I mean, there are times and places where globals may be appropriate, but...

Oh, well: Chacun Ã* son goût!


Regards,

Dave