PartMC  2.6.1
getopt.F90
Go to the documentation of this file.
1 ! ------------------------------------------------------------
2 ! Copyright 2008 by Mark Gates
3 !
4 ! This program is free software; you can redistribute or modify it under
5 ! the terms of the GNU general public license (GPL), version 2 or later.
6 !
7 ! This program is distributed in the hope that it will be useful, but
8 ! WITHOUT ANY WARRANTY; without even the implied warranty of
9 ! merchantability or fitness for a particular purpose.
10 !
11 ! If you wish to incorporate this into non-GPL software, please contact
12 ! me regarding licensing terms.
13 !
14 ! ------------------------------------------------------------
15 ! Fortran 95 getopt() and getopt_long(), similar to those in standard C library.
16 !
17 ! ch = getopt( optstring, [longopts] )
18 ! Returns next option character from command line arguments.
19 ! If an option is not recognized, it returns '?'.
20 ! If no options are left, it returns a null character, char(0).
21 !
22 ! optstring contains characters that are recognized as options.
23 ! If a character is followed by a colon, then it takes a required argument.
24 ! For example, "x" recognizes "-x", while "x:" recognizes "-x arg" or "-xarg".
25 !
26 ! optopt is set to the option character, even if it isn't recognized.
27 ! optarg is set to the option's argument.
28 ! optind has the index of the next argument to process. Initially optind=1.
29 ! Errors are printed by default. Set opterr=.false. to suppress them.
30 !
31 ! Grouped options are allowed, so "-abc" is the same as "-a -b -c".
32 !
33 ! If longopts is present, it is an array of type(option_s), where each entry
34 ! describes one long option.
35 !
36 ! type option_s
37 ! character(len=80) :: name
38 ! logical :: has_arg
39 ! character :: val
40 ! end type
41 !
42 ! The name field is the option name, without the leading -- double dash.
43 ! Set the has_arg field to true if it requires an argument, false if not.
44 ! The val field is returned. Typically this is set to the corresponding short
45 ! option, so short and long options can be processed together. (But there
46 ! is no requirement that every long option has a short option, or vice-versa.)
47 !
48 ! -----
49 ! EXAMPLE
50 ! program test
51 ! use getopt_m
52 ! implicit none
53 ! character:: ch
54 ! type(option_s):: opts(2)
55 ! opts(1) = option_s( "alpha", .false., 'a' )
56 ! opts(2) = option_s( "beta", .true., 'b' )
57 ! do
58 ! select case( getopt( "ab:c", opts ))
59 ! case( char(0))
60 ! exit
61 ! case( 'a' )
62 ! print *, 'option alpha/a'
63 ! case( 'b' )
64 ! print *, 'option beta/b=', optarg
65 ! case( '?' )
66 ! print *, 'unknown option ', optopt
67 ! stop
68 ! case default
69 ! print *, 'unhandled option ', optopt, ' (this is a bug)'
70 ! end select
71 ! end do
72 ! end program test
73 !
74 ! Differences from C version:
75 ! - when options are finished, C version returns -1 instead of char(0),
76 ! and thus stupidly requires an int instead of a char.
77 ! - does not support optreset
78 ! - does not support "--" as last argument
79 ! - if no argument, optarg is blank, not NULL
80 ! - argc and argv are implicit
81 !
82 ! Differences for long options:
83 ! - optional argument to getopt(), rather than separate function getopt_long()
84 ! - has_arg is logical, and does not support optional_argument
85 ! - does not support flag field (and thus always returns val)
86 ! - does not support longindex
87 ! - does not support "--opt=value" syntax, only "--opt value"
88 ! - knows the length of longopts, so does not need an empty last record
89 
90 module getopt_m
91  implicit none
92  character(len=80):: optarg
93  character:: optopt
94  integer:: optind=1
95  logical:: opterr=.true.
96 
97  type option_s
98  character(len=80) :: name
99  logical :: has_arg
100  character :: val
101  end type option_s
102 
103  ! grpind is index of next option within group; always >= 2
104  integer, private:: grpind=2
105 
106 contains
107 
108  ! ----------------------------------------
109  ! Return str(i:j) if 1 <= i <= j <= len(str),
110  ! else return empty string.
111  ! This is needed because Fortran standard allows but doesn't *require* short-circuited
112  ! logical AND and OR operators. So this sometimes fails:
113  ! if ( i < len(str) .and. str(i+1:i+1) == ':' ) then
114  ! but this works:
115  ! if ( substr(str, i+1, i+1) == ':' ) then
116 
117  character function substr( str, i, j )
118  ! arguments
119  character(len=*), intent(in):: str
120  integer, intent(in):: i, j
121 
122  if ( 1 <= i .and. i <= j .and. j <= len(str)) then
123  substr = str(i:j)
124  else
125  substr = ''
126  endif
127  end function substr
128 
129 
130  ! ----------------------------------------
131  character function getopt( optstring, longopts )
132  ! arguments
133  character(len=*), intent(in):: optstring
134  type(option_s), intent(in), optional:: longopts(:)
135 
136  ! local variables
137  character(len=80):: arg
138 
139  optarg = ''
140  if ( optind > iargc()) then
141  getopt = char(0)
142  endif
143 
144  call getarg( optind, arg )
145  if ( present( longopts ) .and. arg(1:2) == '--' ) then
146  getopt = process_long( longopts, arg )
147  elseif ( arg(1:1) == '-' ) then
148  getopt = process_short( optstring, arg )
149  else
150  getopt = char(0)
151  endif
152  end function getopt
153 
154 
155  ! ----------------------------------------
156  character function process_long( longopts, arg )
157  ! arguments
158  type(option_s), intent(in):: longopts(:)
159  character(len=*), intent(in):: arg
160 
161  ! local variables
162  integer:: i
163 
164  ! search for matching long option
165  optind = optind + 1
166  do i = 1, size(longopts)
167  if ( arg(3:) == longopts(i)%name ) then
168  optopt = longopts(i)%val
170  if ( longopts(i)%has_arg ) then
171  if ( optind <= iargc()) then
172  call getarg( optind, optarg )
173  optind = optind + 1
174  elseif ( opterr ) then
175  print '(a,a,a)', "Error: option '", trim(arg), "' requires an argument"
176  endif
177  endif
178  return
179  endif
180  end do
181  ! else not found
182  process_long = '?'
183  if ( opterr ) then
184  print '(a,a,a)', "Error: unrecognized option '", trim(arg), "'"
185  endif
186  end function process_long
187 
188 
189  ! ----------------------------------------
190  character function process_short( optstring, arg )
191  ! arguments
192  character(len=*), intent(in):: optstring, arg
193 
194  ! local variables
195  integer:: i, arglen
196 
197  arglen = len( trim( arg ))
198  optopt = arg(grpind:grpind)
200 
201  i = index( optstring, optopt )
202  if ( i == 0 ) then
203  ! unrecognized option
204  process_short = '?'
205  if ( opterr ) then
206  print '(a,a,a)', "Error: unrecognized option '-", optopt, "'"
207  endif
208  endif
209  if ( i > 0 .and. substr( optstring, i+1, i+1 ) == ':' ) then
210  ! required argument
211  optind = optind + 1
212  if ( arglen > grpind ) then
213  ! -xarg, return remainder of arg
214  optarg = arg(grpind+1:arglen)
215  elseif ( optind <= iargc()) then
216  ! -x arg, return next arg
217  call getarg( optind, optarg )
218  optind = optind + 1
219  elseif ( opterr ) then
220  print '(a,a,a)', "Error: option '-", optopt, "' requires an argument"
221  endif
222  grpind = 2
223  elseif ( arglen > grpind ) then
224  ! no argument (or unrecognized), go to next option in argument (-xyz)
225  grpind = grpind + 1
226  else
227  ! no argument (or unrecognized), go to next argument
228  grpind = 2
229  optind = optind + 1
230  endif
231  end function process_short
232 
233 end module getopt_m
getopt_m::getopt
character function getopt(optstring, longopts)
Definition: getopt.F90:132
getopt_m::process_long
character function process_long(longopts, arg)
Definition: getopt.F90:157
getopt_m::optarg
character(len=80) optarg
Definition: getopt.F90:92
getopt_m::process_short
character function process_short(optstring, arg)
Definition: getopt.F90:191
getopt_m::option_s
Definition: getopt.F90:97
getopt_m
Definition: getopt.F90:90
getopt_m::opterr
logical opterr
Definition: getopt.F90:95
getopt_m::optind
integer optind
Definition: getopt.F90:94
getopt_m::substr
character function substr(str, i, j)
Definition: getopt.F90:118
getopt_m::optopt
character optopt
Definition: getopt.F90:93
getopt_m::grpind
integer, private grpind
Definition: getopt.F90:104