|
M_CLI2
M_CLI2 module (Fortran)
|
Data Types | |
| interface | cgets |
| interface | dgets |
| interface | get_args |
| interface | get_args_fixed_length |
| interface | get_args_fixed_size |
| interface | igets |
| interface | insert |
| interface | lgets |
| interface | locate |
| type | option |
| interface | remove |
| interface | replace |
| interface | rgets |
| interface | sgets |
| interface | str |
Functions/Subroutines | |
| subroutine, private | check_commandline (help_text, version_text) |
| subroutine, public | set_args (prototype, help_text, version_text, string, ierr, errmsg) |
| character(len=:) function, allocatable, public | get_subcommand () |
| subroutine | set_usage (keyword, description, value) |
| recursive subroutine, private | prototype_to_dictionary (string) |
| elemental impure logical function, public | specified (key) |
| subroutine, private | update (key, val) |
| subroutine, private | wipe_dictionary () |
| character(len=:) function, allocatable, private | get (key) |
| subroutine, private | prototype_and_cmd_args_to_nlist (prototype, string) |
| subroutine | expand_response (name) |
| subroutine | get_prototype (name, prototype) |
| integer function | fileopen (filename, message) |
| character(len=:) function, allocatable | get_env (NAME, DEFAULT) |
| character(len=:) function, allocatable | join_path (a1, a2, a3, a4, a5) |
| character(len=:) function, allocatable | get_name () |
| character(:) function, allocatable | basename (path, suffix) |
| character(len=1) function | separator2 () |
| character(len=1) function | separator () |
| subroutine | cmd_args_to_dictionary () |
| subroutine, public | print_dictionary (header, stop) |
| logical function | strtok (source_string, itoken, token_start, token_end, delimiters) |
| subroutine | get_fixedarray_class (keyword, generic, delimiters) |
| subroutine | get_anyarray_l (keyword, larray, delimiters) |
| subroutine | get_anyarray_d (keyword, darray, delimiters) |
| subroutine | get_anyarray_i (keyword, iarray, delimiters) |
| subroutine | get_anyarray_r (keyword, rarray, delimiters) |
| subroutine | get_anyarray_x (keyword, xarray, delimiters) |
| subroutine | get_anyarray_c (keyword, strings, delimiters) |
| subroutine | get_args_fixed_length_a_array (keyword, strings, delimiters) |
| subroutine | get_fixedarray_i (keyword, iarray, delimiters) |
| subroutine | get_fixedarray_r (keyword, rarray, delimiters) |
| subroutine | get_fixed_size_complex (keyword, xarray, delimiters) |
| subroutine | get_fixedarray_d (keyword, darr, delimiters) |
| subroutine | get_fixedarray_l (keyword, larray, delimiters) |
| subroutine | get_fixedarray_fixed_length_c (keyword, strings, delimiters) |
| subroutine | get_scalar_d (keyword, d) |
| subroutine | get_scalar_real (keyword, r) |
| subroutine | get_scalar_i (keyword, i) |
| subroutine | get_scalar_anylength_c (keyword, string) |
| elemental impure subroutine | get_args_fixed_length_scalar_c (keyword, string) |
| subroutine | get_scalar_complex (keyword, x) |
| subroutine | get_scalar_logical (keyword, l) |
| integer function | longest_command_argument () |
| subroutine | journal (where, g0, g1, g2, g3, g4, g5, g6, g7, g8, g9, ga, gb, gc, gd, ge, gf, gg, gh, gi, gj, sep) |
| character(len=:) function, allocatable | msg_scalar (generic0, generic1, generic2, generic3, generic4, generic5, generic6, generic7, generic8, generic9, generica, genericb, genericc, genericd, generice, genericf, genericg, generich, generici, genericj, sep) |
| character(len=:) function, allocatable | msg_one (generic0, generic1, generic2, generic3, generic4, generic5, generic6, generic7, generic8, generic9, sep) |
| character(:) function, allocatable | upper (str) |
| character(:) function, allocatable | lower (str) |
| subroutine | a2i (chars, valu, ierr) |
| subroutine | a2d (chars, valu, ierr, onerr) |
| subroutine | split (input_line, array, delimiters, order, nulls) |
| subroutine | crack_cmd (cmd, old, new, ierr) |
| character(len=:) function, allocatable | replace_str (targetline, old, new, ierr, cmd, range) |
| character(len=:) function, allocatable | quote (str, mode, clip) |
| pure character(len=:) function, allocatable | unquote (quoted_str, esc) |
| character(len=:) function, allocatable | i2s (ivalue, fmt) |
| character(len=:) function, allocatable | merge_str (str1, str2, expr) |
| logical function | decodebase (string, basein, out_baseten) |
| character(len=length) function | lenset (line, length) |
| subroutine | value_to_string (gval, chars, length, err, fmt, trimz) |
| subroutine | trimzeros_ (string) |
| subroutine | substitute (targetline, old, new, ierr, start, end) |
| subroutine, private | locate_c (list, value, place, ier, errmsg) |
| subroutine, private | remove_c (list, place) |
| subroutine, private | remove_l (list, place) |
| subroutine, private | remove_i (list, place) |
| subroutine, private | replace_c (list, value, place) |
| subroutine, private | replace_l (list, value, place) |
| subroutine, private | replace_i (list, value, place) |
| subroutine, private | insert_c (list, value, place) |
| subroutine, private | insert_l (list, value, place) |
| subroutine, private | insert_i (list, value, place) |
| subroutine | many_args (n0, g0, n1, g1, n2, g2, n3, g3, n4, g4, n5, g5, n6, g6, n7, g7, n8, g8, n9, g9, na, ga, nb, gb, nc, gc, nd, gd, ne, ge, nf, gf, ng, gg, nh, gh, ni, gi, nj, gj) |
| integer function, public | iget (n) |
| real function, public | rget (n) |
| real(kind=dp) function, public | dget (n) |
| character(len=:) function, allocatable, public | sget (n) |
| complex function, public | cget (n) |
| logical function, public | lget (n) |
| integer function, dimension(:), allocatable | igs (n) |
| real function, dimension(:), allocatable | rgs (n) |
| real(kind=dp) function, dimension(:), allocatable | dgs (n) |
| character(len=:) function, dimension(:), allocatable | sgs (n, delims) |
| complex function, dimension(:), allocatable | cgs (n) |
| logical function, dimension(:), allocatable | lgs (n) |
| integer function, dimension(:), allocatable | ig () |
| real function, dimension(:), allocatable | rg () |
| real(kind=dp) function, dimension(:), allocatable | dg () |
| logical function, dimension(:), allocatable | lg () |
| complex function, dimension(:), allocatable | cg () |
| character(len=:) function, dimension(:), allocatable | sg () |
| subroutine | mystop (sig, msg) |
| function | atleast (line, length, pattern) |
| subroutine | locate_key (value, place) |
Variables | |
| integer, parameter, private | dp =kind(0.0d0) |
| integer, parameter, private | sp =kind(0.0) |
| logical, save, public | debug_m_cli2 =.false. |
| character(len= *), parameter | gen ='(*(g0))' |
| character(len=:), dimension(:), allocatable, public | unnamed |
| character(len=:), dimension(:), allocatable, public | args |
| character(len=:), allocatable, public | remaining |
| character(len=:), dimension(:), allocatable, save | keywords |
| character(len=:), dimension(:), allocatable, save | shorts |
| character(len=:), dimension(:), allocatable, save | values |
| integer, dimension(:), allocatable, save | counts |
| logical, dimension(:), allocatable, save | present_in |
| logical, dimension(:), allocatable, save | mandatory |
| logical, save | g_keyword_single_letter =.true. |
| character(len=:), allocatable, save | g_passed_in |
| logical, save | g_remaining_on |
| logical, save | g_remaining_option_allowed |
| character(len=:), allocatable, save | g_remaining |
| character(len=:), allocatable, save | g_subcommand |
| character(len=:), allocatable, save | g_stop_message |
| integer, save | g_stop |
| logical, save | g_quiet |
| logical, save | g_strict |
| logical, save, public | cli_response_file =.false. |
| logical, save | g_append |
| logical, save | g_options_only |
| logical, save | g_response |
| character(len=:), allocatable, save | g_response_ignored |
M_CLI2(3fm) - [ARGUMENTS::M_CLI2::INTRO] - command line argument parsing using a prototype command (LICENSE:PD)
Available procedures and variables:
use M_CLI2, only : set_args, get_args, unnamed, remaining, args use M_CLI2, only : get_args_fixed_length, get_args_fixed_size use M_CLI2, only : specified ! convenience functions use M_CLI2, only : dget, iget, lget, rget, sget, cget use M_CLI2, only : dgets, igets, lgets, rgets, sgets, cgets
Allow for command line parsing much like standard Unix command line parsing using a simple prototype.
Typically one call to SET_ARGS(3f) is made to define the command arguments, set default values and parse the command line. Then a call is made to the convenience commands based on GET_ARGS(3f) for each command keyword to obtain the argument values.
The documentation for SET_ARGS(3f) and GET_ARGS(3f) provides further details.
Sample program using type conversion routines
program demo_M_CLI2
use M_CLI2, only : set_args, get_args
use M_CLI2, only : filenames=>unnamed
use M_CLI2, only : get_args_fixed_length, get_args_fixed_size
implicit none
integer :: i
integer,parameter :: dp=kind(0.0d0)
!
! DEFINE ARGS
real :: x, y, z
real(kind=dp),allocatable :: point(:)
logical :: l, lbig
logical,allocatable :: logicals(:)
character(len=:),allocatable :: title ! VARIABLE LENGTH
character(len=40) :: label ! FIXED LENGTH
real :: p(3) ! FIXED SIZE
logical :: logi(3) ! FIXED SIZE
!
! DEFINE AND PARSE (TO SET INITIAL VALUES) COMMAND LINE
! o set a value for all keywords.
! o double-quote strings
! o set all logical values to F or T.
! o value delimiter is comma, colon, or space
call set_args(' &
& -x 1 -y 2 -z 3 &
& -p -1 -2 -3 &
& --point 11.11, 22.22, 33.33e0 &
& --title "my title" -l F -L F &
& --logicals F F F F F &
& -logi F T F &
& --label " " &
! note space between quotes is required
& ')
! ASSIGN VALUES TO ELEMENTS
call get_args('x',x) ! SCALARS
call get_args('y',y)
call get_args('z',z)
call get_args('l',l)
call get_args('L',lbig)
call get_args('title',title) ! ALLOCATABLE STRING
call get_args('point',point) ! ALLOCATABLE ARRAYS
call get_args('logicals',logicals)
!
! for NON-ALLOCATABLE VARIABLES
! for non-allocatable string
call get_args_fixed_length('label',label)
! for non-allocatable arrays
call get_args_fixed_size('p',p)
call get_args_fixed_size('logi',logi)
!
! USE VALUES
write(*,*)'x=',x, 'y=',y, 'z=',z, x+y+z
write(*,*)'p=',p
write(*,*)'point=',point
write(*,*)'title=',title
write(*,*)'label=',label
write(*,*)'l=',l
write(*,*)'L=',lbig
write(*,*)'logicals=',logicals
write(*,*)'logi=',logi
!
! unnamed strings
!
if(size(filenames).gt.0)then
write(*,'(i6.6,3a)')(i,'[',filenames(i),']',i=1,size(filenames))
endif
!
end program demo_M_CLI2
John S. Urban, 2019
Public Domain
|
private |
References decodebase(), i2s(), journal(), substitute(), and unquote().


|
private |
|
private |

|
private |
References split().


|
private |
| complex function, public m_cli2::cget | ( | character(len=*), intent(in) | n | ) |
|
private |
|
private |
check_commandline(3f) - [ARGUMENTS:M_CLI2]check command and process pre-defined options
subroutine check_commandline(help_text,version_text,ierr,errmsg) character(len=:),allocatable,intent(in),optional :: help_text(:) character(len=:),allocatable,intent(in),optional :: version_text(:)
Checks the commandline and processes the implicit –help, –version, –verbose, and –usage parameters.
If the optional text values are supplied they will be displayed by –help and –version command-line options, respectively.
HELP_TEXT if present, will be displayed if program is called with
--help switch, and then the program will terminate. If
not supplied, the command line initialized string will be
shown when --help is used on the commandline.
VERSION_TEXT if present, will be displayed if program is called with
--version switch, and then the program will terminate.
If the first four characters of each line are "@(#)" this prefix
will not be displayed and the last non-blank letter will be
removed from each line. This if for support of the SCCS what(1)
command. If you do not have the what(1) command on GNU/Linux and
Unix platforms you can probably see how it can be used to place
metadata in a binary by entering:
strings demo_commandline|grep '@(#)'|tr '>' '\n'|sed -e 's/ */ /g'
Typical usage:
program check_commandline
use M_CLI2, only : unnamed, set_args, get_args
implicit none
integer :: i
character(len=:),allocatable :: version_text(:), help_text(:)
real :: x, y, z
character(len=*),parameter :: cmd='-x 1 -y 2 -z 3'
version_text=[character(len=80) :: "version 1.0","author: me"]
help_text=[character(len=80) :: "wish I put instructions","here","I suppose?"]
call set_args(cmd,help_text,version_text)
call get_args('x',x,'y',y,'z',z)
! All done cracking the command line. Use the values in your program.
write (*,*)x,y,z
! the optional unnamed values on the command line are
! accumulated in the character array "UNNAMED"
if(size(unnamed).gt.0)then
write (*,'(a)')'files:'
write (*,'(i6.6,3a)') (i,'[',unnamed(i),']',i=1,size(unnamed))
endif
end program check_commandline
References debug_m_cli2, default_help(), g_quiet, g_stop_message, gen, get(), journal(), mystop(), and print_dictionary().


|
private |
References args, debug_m_cli2, expand_response(), g_keyword_single_letter, g_quiet, g_remaining, g_remaining_on, g_remaining_option_allowed, g_response, g_strict, gen, get(), get_next_argument(), ifnull(), keywords, locate_key(), mandatory, mystop(), print_dictionary(), quote(), unnamed, update(), and upper().


|
private |
replace_str(3f) - [M_CLI2:EDITING] function globally replaces one substring for another in string (LICENSE:PD)
function replace_str(targetline[,old,new|cmd],range,ierr) result (newline) character(len=*) :: targetline character(len=*),intent(in),optional :: old character(len=*),intent(in),optional :: new character(len=*),intent(in),optional :: cmd integer,intent(in),optional :: range(2) integer,intent(out),optional :: ierr logical,intent(in),optional :: clip character(len=:),allocatable :: newline
Globally replace one substring for another in string. Either CMD or OLD and NEW must be specified.
targetline input line to be changed old old substring to replace new new substring cmd alternate way to specify old and new string, in the form c/old/new/; where "/" can be any character not in "old" or "new" range if present, only change range(1) to range(2) of occurrences of old string ierr error code. iF ier = -1 bad directive, >= 0 then count of changes made clip whether to return trailing spaces or not. Defaults to .false.
newline allocatable string returned
Sample Program:
program demo_replace_str
use M_CLI2, only : replace_str
implicit none
character(len=:),allocatable :: targetline
targetline='this is the input string'
call testit('th','TH','THis is THe input string')
! a null old substring means "at beginning of line"
call testit('','BEFORE:', 'BEFORE:THis is THe input string')
! a null new string deletes occurrences of the old substring
call testit('i','', 'BEFORE:THs s THe nput strng')
write(*,*)'Examples of the use of RANGE='
targetline=replace_str('a b ab baaa aaaa','a','A')
write(*,*)'replace a with A ['//targetline//']'
targetline=replace_str('a b ab baaa aaaa','a','A',range=[3,5])
write(*,*)'replace a with A instances 3 to 5 ['//targetline//']'
targetline=replace_str('a b ab baaa aaaa','a','',range=[3,5])
write(*,*)'replace a with null instances 3 to 5 ['//targetline//']'
targetline=replace_str('a b ab baaa aaaa aa aa a a a aa aaaaaa','aa','CCCC',range=[3,5])
write(*,*)'replace aa with CCCC instances 3 to 5 ['//targetline//']'
contains
subroutine testit(old,new,expected)
character(len=*),intent(in) :: old,new,expected
write(*,*)repeat('=',79)
write(*,*)':STARTED ['//targetline//']'
write(*,*)':OLD['//old//']', ' NEW['//new//']'
targetline=replace_str(targetline,old,new)
write(*,*)':GOT ['//targetline//']'
write(*,*)':EXPECTED['//expected//']'
write(*,*)':TEST [',targetline.eq.expected,']'
end subroutine testit
end program demo_replace_str
Expected output
STARTED [this is the input string] OLD[th] NEW[TH] GOT [THis is THe input string] EXPECTED[THis is THe input string]
STARTED [THis is THe input string] OLD[] NEW[BEFORE:] GOT [BEFORE:THis is THe input string] EXPECTED[BEFORE:THis is THe input string]
STARTED [BEFORE:THis is THe input string] OLD[i] NEW[] GOT [BEFORE:THs s THe nput strng] EXPECTED[BEFORE:THs s THe nput strng] TEST [ T ] Examples of the use of RANGE= replace a with A [A b Ab bAAA AAAA] replace a with A instances 3 to 5 [a b ab bAAA aaaa] replace a with null instances 3 to 5 [a b ab b aaaa] replace aa with CCCC instances 3 to 5 [a b ab baaa aaCCCC CCCC CCCC a a a aa aaaaaa]
John S. Urban
Public Domain
References journal(), and strtok().


|
private |
decodebase(3f) - [M_CLI2:BASE] convert whole number string in base [2-36] to base 10 number (LICENSE:PD)
logical function decodebase(string,basein,out10)
character(len=*),intent(in) :: string integer,intent(in) :: basein integer,intent(out) :: out10
Convert a numeric string representing a whole number in base BASEIN to base 10. The function returns FALSE if BASEIN is not in the range [2..36] or if string STRING contains invalid characters in base BASEIN or if result OUT10 is too big The letters A,B,...,Z represent 10,11,...,36 in the base > 10.
string input string. It represents a whole number in the base specified by BASEIN unless BASEIN is set to zero. When BASEIN is zero STRING is assumed to be of the form BASE::VALUE where BASE represents the function normally provided by BASEIN. basein base of input string; either 0 or from 2 to 36. out10 output value in base 10
Sample program:
program demo_decodebase
use M_CLI2, only : codebase, decodebase
implicit none
integer :: ba,bd
character(len=40) :: x,y
integer :: r
print *,' BASE CONVERSION'
write(*,'("Start Base (2 to 36): ")',advance='no'); read *, bd
write(*,'("Arrival Base (2 to 36): ")',advance='no'); read *, ba
INFINITE: do
print *,''
write(*,'("Enter number in start base: ")',advance='no'); read *, x
if(x.eq.'0') exit INFINITE
if(decodebase(x,bd,r)) then
if(codebase(r,ba,y)) then
write(*,'("In base ",I2,": ",A20)') ba, y
else
print *,'Error in coding number.'
endif
else
print *,'Error in decoding number.'
endif
enddo INFINITE
end program demo_decodebase
John S. Urban
Ref.: "Math matiques en Turbo-Pascal by M. Ducamp and A. Reverchon (2), Eyrolles, Paris, 1988".
based on a F90 Version By J-P Moreau (www.jpmoreau.fr)
Public Domain
References a2i(), and upper().


|
private |
| real(kind=dp) function, public m_cli2::dget | ( | character(len=*), intent(in) | n | ) |
|
private |
|
private |
References debug_m_cli2, g_append, gen, get_prototype(), and prototype_to_dictionary().


|
private |
|
private |
get(3f) - [ARGUMENTS:M_CLI2] get dictionary value associated with key name in private M_CLI2(3fm) dictionary
Get dictionary value associated with key name in private M_CLI2(3fm) dictionary.
References counts, locate_key(), and values.


|
private |
|
private |
References a2d(), counts, journal(), locate_key(), mystop(), replace_str(), split(), and values.


|
private |
|
private |
|
private |
References get_anyarray_d().


|
private |
References get_anyarray_d(), journal(), and mystop().


|
private |
|
private |
|
private |

|
private |
References get_anyarray_x(), journal(), mystop(), and print_dictionary().


|
private |
get_args(3f) - [ARGUMENTS:M_CLI2] return keyword values when parsing command line arguments (LICENSE:PD)
use M_CLI2, only : get_args ! convenience functions use M_CLI2, only : dget, iget, lget, rget, sget, cget use M_CLI2, only : dgets, igets, lgets, rgets, sgets, cgets subroutine get_args(name,value,delimiters) character(len=*),intent(in) :: name character(len=:),allocatable :: value ! or character(len=:),allocatable :: value(:) ! or [real|doubleprecision|integer|logical|complex] :: value ! or [real|doubleprecision|integer|logical|complex],allocatable :: value(:) character(len=*),intent(in),optional :: delimiters
GET_ARGS(3f) returns the value of keywords after SET_ARGS(3f) has been called. For fixed-length CHARACTER variables see GET_ARGS_FIXED_LENGTH(3f). For fixed-size arrays see GET_ARGS_FIXED_SIZE(3f). As a convenience multiple pairs of keywords and variables may be specified if and only if all the values are scalars and the CHARACTER variables are fixed-length or pre-allocated.
NAME name of commandline argument to obtain the value of
VALUE variable to hold returned value. The kind of the value
is used to determine the type of returned value. May
be a scalar or allocatable array. If type is CHARACTER
the scalar must have an allocatable length.
DELIMITERS By default the delimiter for array values are comma,
colon, and whitespace. A string containing an alternate
list of delimiter characters may be supplied.
There are convenience functions that are replacements for calls to
get_args(3f) for each supported default intrinsic type
o scalars -- dget(3f), iget(3f), lget(3f), rget(3f), sget(3f),
cget(3f)
o vectors -- dgets(3f), igets(3f), lgets(3f), rgets(3f),
sgets(3f), cgets(3f)
D is for DOUBLEPRECISION, I for INTEGER, L for LOGICAL, R for REAL,
S for string (CHARACTER), and C for COMPLEX.
If the functions are called with no argument they will return the
UNNAMED array converted to the specified type.
Sample program:
program demo_get_args
use M_CLI2, only : filenames=>unnamed, set_args, get_args
implicit none
integer :: i
! DEFINE ARGS
real :: x, y, z
real,allocatable :: p(:)
character(len=:),allocatable :: title
logical :: l, lbig
! DEFINE AND PARSE (TO SET INITIAL VALUES) COMMAND LINE
! o only quote strings and use double-quotes
! o set all logical values to F or T.
call set_args(' &
&-x 1 -y 2 -z 3 &
&-p -1,-2,-3 &
&--title "my title" &
& -l F -L F &
& --label " " &
& ')
! ASSIGN VALUES TO ELEMENTS
! SCALARS
call get_args('x',x,'y',y,'z',z)
call get_args('l',l)
call get_args('L',lbig)
! ALLOCATABLE STRING
call get_args('title',title)
! NON-ALLOCATABLE ARRAYS
call get_args('p',p)
! USE VALUES
write(*,'(1x,g0,"=",g0)')'x',x, 'y',y, 'z',z
write(*,*)'p=',p
write(*,*)'title=',title
write(*,*)'l=',l
write(*,*)'L=',lbig
if(size(filenames).gt.0)then
write(*,'(i6.6,3a)')(i,'[',filenames(i),']',i=1,size(filenames))
endif
end program demo_get_args
John S. Urban, 2019
Public Domain
get_args_fixed_length(3f) - [ARGUMENTS:M_CLI2] return keyword values for fixed-length string when parsing command line (LICENSE:PD)
subroutine get_args_fixed_length(name,value) character(len=:),allocatable :: value character(len=*),intent(in),optional :: delimiters
GET_ARGS_fixed_length(3f) returns the value of a string keyword when the string value is a fixed-length CHARACTER variable.
NAME name of commandline argument to obtain the value of
VALUE variable to hold returned value.
Must be a fixed-length CHARACTER variable.
DELIMITERS By default the delimiter for array values are comma,
colon, and whitespace. A string containing an alternate
list of delimiter characters may be supplied.
Sample program:
program demo_get_args_fixed_length
use M_CLI2, only : set_args, get_args_fixed_length
implicit none
! DEFINE ARGS
character(len=80) :: title
call set_args(' &
& -title "my title" &
& ')
! ASSIGN VALUES TO ELEMENTS
call get_args_fixed_length('title',title)
! USE VALUES
write(*,*)'title=',title
end program demo_get_args_fixed_length
John S. Urban, 2019
Public Domain
get_args_fixed_size(3f) - [ARGUMENTS:M_CLI2] return keyword values for fixed-size array when parsing command line arguments (LICENSE:PD)
subroutine get_args_fixed_size(name,value)
[real|doubleprecision|integer|logical|complex] :: value(NNN)
or
character(len=MMM) :: value(NNN)
character(len=*),intent(in),optional :: delimiters
GET_ARGS_FIXED_SIZE(3f) returns the value of keywords for fixed-size arrays after SET_ARGS(3f) has been called. On input on the command line all values of the array must be specified.
NAME name of commandline argument to obtain the value of
VALUE variable to hold returned values. The kind of the value is used to determine the type of returned value. Must be a fixed-size array. If type is CHARACTER the length must also be fixed.
DELIMITERS By default the delimiter for array values are comma, colon, and whitespace. A string containing an alternate list of delimiter characters may be supplied.
Sample program:
program demo_get_args_fixed_size
use M_CLI2, only : set_args, get_args_fixed_size
implicit none
integer,parameter :: dp=kind(0.0d0)
! DEFINE ARGS
real :: x(2)
real(kind=dp) :: y(2)
integer :: p(3)
character(len=80) :: title(1)
logical :: l(4), lbig(4)
complex :: cmp(2)
! DEFINE AND PARSE (TO SET INITIAL VALUES) COMMAND LINE
! o only quote strings
! o set all logical values to F or T.
call set_args(' &
& -x 10.0,20.0 &
& -y 11.0,22.0 &
& -p -1,-2,-3 &
& -title "my title" &
& -l F,T,F,T -L T,F,T,F &
& --cmp 111,222.0,333.0e0,4444 &
& ')
! ASSIGN VALUES TO ELEMENTS
call get_args_fixed_size('x',x)
call get_args_fixed_size('y',y)
call get_args_fixed_size('p',p)
call get_args_fixed_size('title',title)
call get_args_fixed_size('l',l)
call get_args_fixed_size('L',lbig)
call get_args_fixed_size('cmp',cmp)
! USE VALUES
write(*,*)'x=',x
write(*,*)'p=',p
write(*,*)'title=',title
write(*,*)'l=',l
write(*,*)'L=',lbig
write(*,*)'cmp=',cmp
end program demo_get_args_fixed_size
Results:
John S. Urban, 2019
Public Domain
References dp, get_fixed_size_complex(), get_fixedarray_d(), get_fixedarray_fixed_length_c(), get_fixedarray_i(), get_fixedarray_l(), get_fixedarray_r(), and mystop().

|
private |
References get_anyarray_d(), journal(), mystop(), and print_dictionary().


|
private |
References counts, journal(), locate_key(), mystop(), print_dictionary(), split(), unquote(), and values.


|
private |
References get_anyarray_d(), journal(), mystop(), and print_dictionary().


|
private |
References get_anyarray_l(), journal(), mystop(), and print_dictionary().


|
private |
References get_anyarray_r(), journal(), mystop(), and print_dictionary().


|
private |

|
private |
References basename(), debug_m_cli2, find_and_read_response_file(), gen, get_env(), and get_name().


|
private |
|
private |
References get_fixedarray_d(), journal(), mystop(), and sp.

|
private |
References get_anyarray_d(), journal(), mystop(), and print_dictionary().


|
private |
|
private |
|
private |
| character(len=:) function, allocatable, public m_cli2::get_subcommand |
get_subcommand(3f) - [ARGUMENTS:M_CLI2] special-case routine for handling subcommands on a command line (LICENSE:PD)
function get_subcommand() character(len=:),allocatable :: get_subcommand
In the special case when creating a program with subcommands it is assumed the first word on the command line is the subcommand. A routine is required to handle response file processing, therefore this routine (optionally processing response files) returns that first word as the subcommand name.
It should not be used by programs not building a more elaborate command with subcommands.
NAME name of subcommand
Sample program:
program demo_get_subcommand !x! SUBCOMMANDS !x! For a command with subcommands like git(1) !x! you can make separate namelists for each subcommand. !x! You can call this program which has two subcommands (run, test), !x! like this: !x! demo_get_subcommand –help !x! demo_get_subcommand run -x -y -z -title -l -L !x! demo_get_subcommand test -title -l -L -testname !x! demo_get_subcommand run –help implicit none !x! DEFINE VALUES TO USE AS ARGUMENTS WITH INITIAL VALUES real :: x=-999.0,y=-999.0,z=-999.0 character(len=80) :: title="not set" logical :: l=.false. logical :: l_=.false. character(len=80) :: testname="not set" character(len=20) :: name call parse(name) !x! DEFINE AND PARSE COMMAND LINE !x! ALL DONE CRACKING THE COMMAND LINE. !x! USE THE VALUES IN YOUR PROGRAM. write(*,*)'command was ',name write(*,*)'x,y,z .... ',x,y,z write(*,*)'title .... ',title write(*,*)'l,l_ ..... ',l,l_ write(*,*)'testname . ',testname contains subroutine parse(name) !x! PUT EVERYTHING TO DO WITH COMMAND PARSING HERE FOR CLARITY use M_CLI2, only : set_args, get_args, get_args_fixed_length use M_CLI2, only : get_subcommand use M_CLI2, only : CLI_RESPONSE_FILE character(len=*) :: name ! the subcommand name character(len=:),allocatable :: help_text(:), version_text(:) CLI_RESPONSE_FILE=.true. ! define version text version_text=[character(len=80) :: & '@(#)PROGRAM: demo_get_subcommand >', & '@(#)DESCRIPTION: My demo program >', & '@(#)VERSION: 1.0 20200715 >', & '@(#)AUTHOR: me, myself, and I>', & '@(#)LICENSE: Public Domain >', & '' ] ! general help for "demo_get_subcommand --help" help_text=[character(len=80) :: & ' allowed subcommands are ', & ' * run -l -L -title -x -y -z ', & ' * test -l -L -title ', & '' ] ! find the subcommand name by looking for first word on command ! not starting with dash name = get_subcommand() select case(name) case('run') help_text=[character(len=80) :: & ' ', & ' Help for subcommand "run" ', & ' ', & '' ] call set_args( & & '-x 1 -y 2 -z 3 –title "my title" -l F -L F',& & help_text,version_text) call get_args('x',x) call get_args('y',y) call get_args('z',z) call get_args_fixed_length('title',title) call get_args('l',l) call get_args('L',l_) case('test') help_text=[character(len=80) :: & ' ', & ' Help for subcommand "test" ', & ' ', & '' ] call set_args(& & '–title "my title" -l F -L F –testname "Test"',& & help_text,version_text) call get_args_fixed_length('title',title) call get_args('l',l) call get_args('L',l_) call get_args_fixed_length('testname',testname) case default ! process help and version call set_args(' ',help_text,version_text) write(*,'(*(a))')'unknown or missing subcommand [',trim(name),']' write(*,'(a)')[character(len=80) :: & ' allowed subcommands are ', & ' * run -l -L -title -x -y -z ', & ' * test -l -L -title ', & '' ] stop end select end subroutine parse end program demo_get_subcommand
John S. Urban, 2019
Public Domain
References g_options_only, g_subcommand, get_prototype(), longest_command_argument(), split(), and unnamed.

|
private |
References value_to_string().


|
private |
| integer function, public m_cli2::iget | ( | character(len=*), intent(in) | n | ) |
|
private |
|
private |
insert(3f) - [M_CLI2] insert entry into a string array at specified position (LICENSE:PD)
subroutine insert(list,value,place)
character(len=*)|doubleprecision|real|integer,intent(in) :: value character(len=:)|doubleprecision|real|integer,intent(in) :: list(:) integer,intent(in) :: place
Insert a value into an allocatable array at the specified index. The list and value must be of the same type (CHARACTER, DOUBLEPRECISION, REAL, or INTEGER)
list is the list array. Must be sorted in descending order. value the value to place in the array PLACE is the subscript that the entry should be placed at
Find if a string is in a sorted array, and insert the string into the list if it is not present ...
program demo_insert
use M_sort, only : sort_shell
use M_CLI2, only : locate, insert
implicit none
character(len=:),allocatable :: arr(:)
integer :: i
arr=[character(len=20) :: '', 'ZZZ', 'aaa', 'b', 'xxx' ]
! make sure sorted in descending order
call sort_shell(arr,order='d')
! add or replace values
call update(arr,'b')
call update(arr,'[')
call update(arr,'c')
call update(arr,'ZZ')
call update(arr,'ZZZ')
call update(arr,'ZZZZ')
call update(arr,'')
call update(arr,'z')
contains
subroutine update(arr,string)
character(len=:),allocatable :: arr(:)
character(len=*) :: string
integer :: place, end
end=size(arr)
! find where string is or should be
call locate(arr,string,place)
! if string was not found insert it
if(place.lt.1)then
call insert(arr,string,abs(place))
endif
! show array
end=size(arr)
write(*,'("array is now SIZE=",i0,1x,*(a,","))')end,(trim(arr(i)),i=1,end)
end subroutine update
end program demo_insert
Results:
array is now SIZE=5 xxx,b,aaa,ZZZ,, array is now SIZE=6 xxx,b,aaa,[,ZZZ,, array is now SIZE=7 xxx,c,b,aaa,[,ZZZ,, array is now SIZE=8 xxx,c,b,aaa,[,ZZZ,ZZ,, array is now SIZE=9 xxx,c,b,aaa,[,ZZZZ,ZZZ,ZZ,, array is now SIZE=10 z,xxx,c,b,aaa,[,ZZZZ,ZZZ,ZZ,,
1989,2017 John S. Urban
Public Domain
|
private |
|
private |
|
private |
References separator(), and substitute().


|
private |
|
private |
lenset(3f) - [M_CLI2:LENGTH] return string trimmed or padded to specified length (LICENSE:PD)
function lenset(str,length) result(strout) character(len=*) :: str character(len=length) :: strout integer,intent(in) :: length
lenset(3f) truncates a string or pads it with spaces to the specified length.
str input string length output string length
strout output string
Sample Program:
program demo_lenset
use M_CLI2, only : lenset
implicit none
character(len=10) :: string='abcdefghij'
character(len=:),allocatable :: answer
answer=lenset(string,5)
write(*,'("[",a,"]")') answer
answer=lenset(string,20)
write(*,'("[",a,"]")') answer
end program demo_lenset
Expected output:
[abcde] [abcdefghij ]
John S. Urban
Public Domain

|
private |
| logical function, public m_cli2::lget | ( | character(len=*), intent(in) | n | ) |
|
private |
|
private |
locate(3f) - [M_CLI2] finds the index where a string is found or should be in a sorted array (LICENSE:PD)
subroutine locate(list,value,place,ier,errmsg)
character(len=:)|doubleprecision|real|integer,allocatable :: list(:) character(len=*)|doubleprecision|real|integer,intent(in) :: value integer, intent(out) :: PLACE
integer, intent(out),optional :: IER character(len=*),intent(out),optional :: ERRMSG
LOCATE(3f) finds the index where the VALUE is found or should be found in an array. The array must be sorted in descending order (highest at top). If VALUE is not found it returns the index where the name should be placed at with a negative sign. The array and list must be of the same type (CHARACTER, DOUBLEPRECISION, REAL,INTEGER)
VALUE the value to locate in the list. LIST is the list array.
PLACE is the subscript that the entry was found at if it is greater than zero(0).
If PLACE is negative, the absolute value of PLACE indicates the subscript value where the new entry should be placed in order to keep the list alphabetized.
IER is zero(0) if no error occurs. If an error occurs and IER is not present, the program is stopped.
ERRMSG description of any error
Find if a string is in a sorted array, and insert the string into the list if it is not present ...
program demo_locate
use M_sort, only : sort_shell
use M_CLI2, only : locate
implicit none
character(len=:),allocatable :: arr(:)
integer :: i
arr=[character(len=20) :: '', 'ZZZ', 'aaa', 'b', 'xxx' ]
! make sure sorted in descending order
call sort_shell(arr,order='d')
call update(arr,'b')
call update(arr,'[')
call update(arr,'c')
call update(arr,'ZZ')
call update(arr,'ZZZZ')
call update(arr,'z')
contains
subroutine update(arr,string)
character(len=:),allocatable :: arr(:)
character(len=*) :: string
integer :: place, plus, ii, end
! find where string is or should be
call locate(arr,string,place)
write(*,*)'for "'//string//'" index is ',place, size(arr)
! if string was not found insert it
if(place.lt.1)then
plus=abs(place)
ii=len(arr)
end=size(arr)
! empty array
if(end.eq.0)then
arr=[character(len=ii) :: string ]
! put in front of array
elseif(plus.eq.1)then
arr=[character(len=ii) :: string, arr]
! put at end of array
elseif(plus.eq.end)then
arr=[character(len=ii) :: arr, string ]
! put in middle of array
else
arr=[character(len=ii) :: arr(:plus-1), string,arr(plus:) ]
endif
! show array
write(*,'("SIZE=",i0,1x,*(a,","))')end,(trim(arr(i)),i=1,end)
endif
end subroutine update
end program demo_locate
Results:
for "b" index is 2 5 for "[" index is -4 5 SIZE=5 xxx,b,aaa,[,ZZZ, for "c" index is -2 6 SIZE=6 xxx,c,b,aaa,[,ZZZ, for "ZZ" index is -7 7 SIZE=7 xxx,c,b,aaa,[,ZZZ,, for "ZZZZ" index is -6 8 SIZE=8 xxx,c,b,aaa,[,ZZZZ,ZZZ,, for "z" index is -1 9 SIZE=9 z,xxx,c,b,aaa,[,ZZZZ,ZZZ,,
1989,2017 John S. Urban
Public Domain
References mystop().

|
private |
|
private |
longest_command_argument(3f) - [ARGUMENTS:M_args] length of longest argument on command line (LICENSE:PD)
function longest_command_argument() result(ilongest) integer :: ilongest
length of longest argument on command line. Useful when allocating storage for holding arguments.
longest_command_argument length of longest command argument
Sample program
program demo_longest_command_argument
use M_args, only : longest_command_argument
write(*,*)'longest argument is ',longest_command_argument()
end program demo_longest_command_argument
John S. Urban, 2019
Public Domain

|
private |

|
private |
|
private |
merge_str(3f) - [M_CLI2:LENGTH] pads strings to same length and then calls MERGE(3f) (LICENSE:PD)
function merge_str(str1,str2,expr) result(strout) character(len=*),intent(in),optional :: str1 character(len=*),intent(in),optional :: str2 logical,intent(in) :: expr character(len=:),allocatable :: strout
merge_str(3f) pads the shorter of str1 and str2 to the longest length of str1 and str2 and then calls MERGE(padded_str1,padded_str2,expr). It trims trailing spaces off the result and returns the trimmed string. This makes it easier to call MERGE(3f) with strings, as MERGE(3f) requires the strings to be the same length.
NOTE: STR1 and STR2 are always required even though declared optional. this is so the call "STR_MERGE(A,B,present(A))" is a valid call. The parameters STR1 and STR2 when they are optional parameters can be passed to a procedure if the options are optional on the called procedure.
STR1 string to return if the logical expression EXPR is true STR2 string to return if the logical expression EXPR is false EXPR logical expression to evaluate to determine whether to return STR1 when true, and STR2 when false.
MERGE_STR a trimmed string is returned that is otherwise the value of STR1 or STR2, depending on the logical expression EXPR.
Sample Program:
program demo_merge_str
use M_CLI2, only : merge_str
implicit none
character(len=:), allocatable :: answer
answer=merge_str('first string', 'second string is longer',10.eq.10)
write(*,'("[",a,"]")') answer
answer=merge_str('first string', 'second string is longer',10.ne.10)
write(*,'("[",a,"]")') answer
end program demo_merge_str
Expected output
[first string] [second string is longer]
John S. Urban
Public Domain
References lenset().


|
private |
|
private |
str(3f) - [M_CLI2] converts any standard scalar type to a string (LICENSE:PD)
function str(g0,g1,g2,g3,g4,g5,g6,g7,g8,g9,ga,gb,gc,gd,ge,gf,gg,gh,gi,gj,sep) class(*),intent(in),optional :: g0,g1,g2,g3,g4,g5,g6,g7,g8,g9 class(*),intent(in),optional :: ga,gb,gc,gd,ge,gf,gg,gh,gi,gj character(len=*),intent(in),optional :: sep character,len=(:),allocatable :: str
str(3f) builds a space-separated string from up to twenty scalar values.
g[0-9a-j] optional value to print the value of after the message. May be of type INTEGER, LOGICAL, REAL, DOUBLEPRECISION, COMPLEX, or CHARACTER.
Optionally, all the generic values can be single-dimensioned arrays. Currently, mixing scalar arguments and array arguments is not supported.
sep separator to place between values. Defaults to a space.
str description to print
Sample program:
program demo_msg
use M_CLI2, only : str
implicit none
character(len=:),allocatable :: pr
character(len=:),allocatable :: frmt
integer :: biggest
pr=str('HUGE(3f) integers',huge(0),'and real',huge(0.0),'and double',huge(0.0d0))
write(*,'(a)')pr
pr=str('real :',huge(0.0),0.0,12345.6789,tiny(0.0) )
write(*,'(a)')pr
pr=str('doubleprecision :',huge(0.0d0),0.0d0,12345.6789d0,tiny(0.0d0) )
write(*,'(a)')pr
pr=str('complex :',cmplx(huge(0.0),tiny(0.0)) )
write(*,'(a)')pr
! create a format on the fly
biggest=huge(0)
frmt=str('(*(i',int(log10(real(biggest))),':,1x))',sep=' ')
write(*,*)'format=',frmt
! although it will often work, using str(3f) in an I/O statement is not recommended
! because if an error occurs str(3f) will try to write while part of an I/O statement
! which not all compilers can handle and is currently non-standard
write(*,*)str('program will now stop')
end program demo_msg
Output
HUGE(3f) integers 2147483647 and real 3.40282347E+38 and double 1.7976931348623157E+308 real : 3.40282347E+38 0.00000000 12345.6787 1.17549435E-38 doubleprecision : 1.7976931348623157E+308 0.0000000000000000 12345.678900000001 2.2250738585072014E-308 complex : (3.40282347E+38,1.17549435E-38) format=(*(i9:,1x)) program will now stop
John S. Urban
Public Domain
References debug_m_cli2, gen, and print_generic().

|
private |
References g_quiet, g_stop, g_stop_message, and journal().


| subroutine, public m_cli2::print_dictionary | ( | character(len=*), intent(in), optional | header, |
| logical, intent(in), optional | stop | ||
| ) |
print_dictionary(3f) - [ARGUMENTS:M_CLI2] print internal dictionary created by calls to set_args(3f) (LICENSE:PD)
subroutine print_dictionary(header,stop) character(len=*),intent(in),optional :: header logical,intent(in),optional :: stop
Print the internal dictionary created by calls to set_args(3f). This routine is intended to print the state of the argument list if an error occurs in using the set_args(3f) procedure.
HEADER label to print before printing the state of the command argument list. STOP logical value that if true stops the program after displaying the dictionary.
Typical usage:
program demo_print_dictionary
use M_CLI2, only : set_args, get_args
implicit none
real :: x, y, z
call set_args('-x 10 -y 20 -z 30')
call get_args('x',x,'y',y,'z',z)
! all done cracking the command line; use the values in your program.
write(*,*)x,y,z
end program demo_print_dictionary
Sample output
Calling the sample program with an unknown parameter or the --usage
switch produces the following:
$ ./demo_print_dictionary -A
UNKNOWN SHORT KEYWORD: -A
KEYWORD PRESENT VALUE
z F [3]
y F [2]
x F [1]
help F [F]
version F [F]
usage F [F]
John S. Urban, 2019
Public Domain
References args, atleast(), counts, g_quiet, g_remaining, keywords, mystop(), present_in, shorts, unnamed, and values.


|
private |
prototype_and_cmd_args_to_nlist(3f) - [ARGUMENTS:M_CLI2] convert Unix-like command arguments to table (LICENSE:PD)
subroutine prototype_and_cmd_args_to_nlist(prototype) character(len=*) :: prototype
create dictionary with character keywords, values, and value lengths using the routines for maintaining a list from command line arguments.
prototype
Sample program
program demo_prototype_and_cmd_args_to_nlist
use M_CLI2, only : prototype_and_cmd_args_to_nlist, unnamed
implicit none
character(len=:),allocatable :: readme
character(len=256) :: message
integer :: ios
integer :: i
doubleprecision :: something
! define arguments
logical :: l,h,v
real :: p(2)
complex :: c
doubleprecision :: x,y,z
! uppercase keywords get an underscore to make it easier o remember
logical :: l_,h_,v_
character(len=256) :: a_,b_ ! character variables must be long enough to hold returned value
integer :: c_(3)
! give command template with default values
! all values except logicals get a value.
! strings must be delimited with double quotes
! A string has to have at least one character as for -A
! lists of numbers should be comma-delimited. No spaces are allowed in lists of numbers
call prototype_and_cmd_args_to_nlist('&
& -l -v -h -LVH -x 0 -y 0.0 -z 0.0d0 -p 0,0 &
& -A " " -B "Value B" -C 10,20,30 -c (-123,-456)',readme)
call get_args('x',x,'y',y,'z',z)
something=sqrt(x**2+y**2+z**2)
write (*,*)something,x,y,z
if(size(unnamed).gt.0)then
write (*,'(a)')'files:'
write (*,'(i6.6,3a)')(i,'[',unnamed(i),']',i=1,size(unnamed))
endif
end program demo_prototype_and_cmd_args_to_nlist
John S. Urban, 2019
Public Domain
References args, cmd_args_to_dictionary(), debug_m_cli2, g_passed_in, g_remaining, g_remaining_on, g_remaining_option_allowed, g_strict, gen, locate_key(), longest_command_argument(), present_in, prototype_to_dictionary(), remaining, unnamed, and update().


|
private |
prototype_to_dictionary(3f) - [ARGUMENTS:M_CLI2] parse user command and store tokens into dictionary (LICENSE:PD)
recursive subroutine prototype_to_dictionary(string) character(len=*),intent(in) :: string
given a string of form
-var value -var value
define dictionary of form
keyword(i), value(i)
o string values
o must be delimited with double quotes. o adjacent double quotes put one double quote into value o must not be null. A blank is specified as " ", not "".
o logical values
o logical values must have a value
o leading and trailing blanks are removed from unquoted values
STRING string is character input string to define command
sample program:
Results:
John S. Urban, 2019
Public Domain
References debug_m_cli2, g_keyword_single_letter, g_remaining_option_allowed, g_response_ignored, gen, locate_key(), and update().


|
private |
quote(3f) - [M_CLI2:QUOTES] add quotes to string as if written with list-directed input (LICENSE:PD)
function quote(str,mode,clip) result (quoted_str)
character(len=*),intent(in) :: str character(len=*),optional,intent(in) :: mode logical,optional,intent(in) :: clip character(len=:),allocatable :: quoted_str
Add quotes to a CHARACTER variable as if it was written using list-directed input. This is particularly useful for processing strings to add to CSV files.
str input string to add quotes to, using the rules of list-directed input (single quotes are replaced by two adjacent quotes) mode alternate quoting methods are supported:
DOUBLE default. replace quote with double quotes
ESCAPE replace quotes with backslash-quote instead of double quotes
clip default is to trim leading and trailing spaces from the string. If CLIP is .FALSE. spaces are not trimmed
quoted_str The output string, which is based on adding quotes to STR.
Sample program:
program demo_quote
use M_CLI2, only : quote
implicit none
character(len=:),allocatable :: str
character(len=1024) :: msg
integer :: ios
character(len=80) :: inline
do
write(*,'(a)',advance='no')'Enter test string:'
read(*,'(a)',iostat=ios,iomsg=msg)inline
if(ios.ne.0)then
write(*,*)trim(inline)
exit
endif
! the original string
write(*,'(a)')'ORIGINAL ['//trim(inline)//']'
! the string processed by quote(3f)
str=quote(inline)
write(*,'(a)')'QUOTED ['//str//']'
! write the string list-directed to compare the results
write(*,'(a)',iostat=ios,iomsg=msg) 'LIST DIRECTED:'
write(*,*,iostat=ios,iomsg=msg,delim='none') inline
write(*,*,iostat=ios,iomsg=msg,delim='quote') inline
write(*,*,iostat=ios,iomsg=msg,delim='apostrophe') inline
enddo
end program demo_quote
John S. Urban
Public Domain
References journal(), lower(), merge_str(), and replace_str().


|
private |
remove(3f) - [M_CLI2] remove entry from an allocatable array at specified position (LICENSE:PD)
subroutine remove(list,place)
character(len=:)|doubleprecision|real|integer,intent(inout) :: list(:) integer, intent(out) :: PLACE
Remove a value from an allocatable array at the specified index. The array is assumed to be sorted in descending order. It may be of type CHARACTER, DOUBLEPRECISION, REAL, or INTEGER.
list is the list array. PLACE is the subscript for the entry that should be removed
Sample program
program demo_remove
use M_sort, only : sort_shell
use M_CLI2, only : locate, remove
implicit none
character(len=:),allocatable :: arr(:)
integer :: i
integer :: end
arr=[character(len=20) :: '', 'ZZZ', 'Z', 'aaa', 'b', 'b', 'ab', 'bb', 'xxx' ]
! make sure sorted in descending order
call sort_shell(arr,order='d')
end=size(arr)
write(*,'("SIZE=",i0,1x,*(a,","))')end,(trim(arr(i)),i=1,end)
call remove(arr,1)
end=size(arr)
write(*,'("SIZE=",i0,1x,*(a,","))')end,(trim(arr(i)),i=1,end)
call remove(arr,4)
end=size(arr)
write(*,'("SIZE=",i0,1x,*(a,","))')end,(trim(arr(i)),i=1,end)
end program demo_remove
Results:
Expected output
SIZE=9 xxx,bb,b,b,ab,aaa,ZZZ,Z,, SIZE=8 bb,b,b,ab,aaa,ZZZ,Z,, SIZE=7 bb,b,b,aaa,ZZZ,Z,,
1989,2017 John S. Urban
Public Domain
|
private |
|
private |
|
private |
replace(3f) - [M_CLI2] replace entry in a string array at specified position (LICENSE:PD)
subroutine replace(list,value,place)
character(len=*)|doubleprecision|real|integer,intent(in) :: value character(len=:)|doubleprecision|real|integer,intent(in) :: list(:) integer, intent(out) :: PLACE
replace a value in an allocatable array at the specified index. Unless the array needs the string length to increase this is merely an assign of a value to an array element. The array may be of type CHARACTER, DOUBLEPRECISION, REAL, or INTEGER> It is assumed to be sorted in descending order without duplicate values. The value and list must be of the same type.
VALUE the value to place in the array LIST is the array. PLACE is the subscript that the entry should be placed at
Replace key-value pairs in a dictionary
program demo_replace
use M_CLI2, only : insert, locate, replace
! Find if a key is in a list and insert it
! into the key list and value list if it is not present
! or replace the associated value if the key existed
implicit none
character(len=20) :: key
character(len=100) :: val
character(len=:),allocatable :: keywords(:)
character(len=:),allocatable :: values(:)
integer :: i
integer :: place
call update('b','value of b')
call update('a','value of a')
call update('c','value of c')
call update('c','value of c again')
call update('d','value of d')
call update('a','value of a again')
! show array
write(*,'(*(a,"==>",a,/))')(trim(keywords(i)),trim(values(i)),i=1,size(keywords))
call locate_key('a',place)
if(place.gt.0)then
write(*,*)'The value of "a" is',trim(values(place))
else
write(*,*)'"a" not found'
endif
contains
subroutine update(key,val)
character(len=*),intent(in) :: key
character(len=*),intent(in) :: val
integer :: place
! find where string is or should be
call locate_key(key,place)
! if string was not found insert it
if(place.lt.1)then
call insert(keywords,key,abs(place))
call insert(values,val,abs(place))
else ! replace
call replace(values,val,place)
endif
end subroutine update
end program demo_replace
Expected output
d==>value of d c==>value of c again b==>value of b a==>value of a again
1989,2017 John S. Urban
Public Domain
|
private |
|
private |
|
private |
References crack_cmd(), and journal().


|
private |
| real function, public m_cli2::rget | ( | character(len=*), intent(in) | n | ) |
|
private |
|
private |
separator(3f) - [M_io:ENVIRONMENT] try to determine pathname directory separator character (LICENSE:PD)
function separator() result(sep) character(len=1) :: sep
First testing for the existence of "/.", then if that fails a list of variable names assumed to contain directory paths {PATH|HOME} are examined first for a backslash, then a slash. Assuming basically the choice is a ULS or MSWindows system, and users can do weird things like put a backslash in a ULS path and break it.
Therefore can be very system dependent. If the queries fail the default returned is "/".
sample usage
program demo_separator use M_io, only : separator implicit none write(*,*)'separator=',separator() end program demo_separator
References get_env().


|
private |
| subroutine, public m_cli2::set_args | ( | character(len=*), intent(in) | prototype, |
| character(len=:), dimension(:), intent(in), optional, allocatable | help_text, | ||
| character(len=:), dimension(:), intent(in), optional, allocatable | version_text, | ||
| character(len=*), intent(in), optional | string, | ||
| integer, intent(out), optional | ierr, | ||
| character(len=:), intent(out), optional, allocatable | errmsg | ||
| ) |
set_args(3f) - [ARGUMENTS:M_CLI2] command line argument parsing (LICENSE:PD)
subroutine set_args(definition,help_text,version_text,ierr,errmsg) character(len=*),intent(in),optional :: definition character(len=:),intent(in),allocatable,optional :: help_text character(len=:),intent(in),allocatable,optional :: version_text integer,intent(out),optional :: ierr character(len=:),intent(out),allocatable,optional :: errmsg
SET_ARGS(3f) requires a unix-like command prototype for defining arguments and default command-line options. Argument values are then read using GET_ARGS(3f). The --help and --version options require the optional help_text and version_text values to be provided.
DESCRIPTION composed of all command arguments concatenated
into a Unix-like command prototype string. For
example:
call set_args('-L F -ints 10,20,30 -title "my title" -R 10.3')
DESCRIPTION is pre-defined to act as if started with
the reserved options '--verbose F --usage F --help
F --version F'. The --usage option is processed when
the set_args(3f) routine is called. The same is true
for --help and --version if the optional help_text
and version_text options are provided.
see "DEFINING THE PROTOTYPE" in the next section for
further details.
HELP_TEXT if present, will be displayed if program is called with
--help switch, and then the program will terminate. If
not supplied, the command line initialization string
will be shown when --help is used on the commandline.
VERSION_TEXT if present, will be displayed if program is called with
--version switch, and then the program will terminate.
IERR if present a non-zero option is returned when an
error occurs instead of program execution being
terminated
ERRMSG a description of the error if ierr is present
o all keywords on the prototype MUST get a value.
o logicals MUST be set to F or T.
o strings MUST be delimited with double-quotes and must be at least one space. Internal double-quotes are represented with two double-quotes.
o numeric keywords are not allowed; but this allows negative numbers to be used as values.
o lists of values should be comma-delimited unless a user-specified delimiter is used. The prototype must use the same array delimiters as the call to the family of get_args*(3f) called.
o long names (–keyword) should be all lowercase
o The simplest way to have short names is to suffix the long name with :LETTER If this syntax is used then logical shorts may be combined on the command line and – and - prefixes are strictly enforced.
mapping of short names to long names not using the –LONGNAME:SHORTNAME syntax is demonstrated in the manpage for SPECIFIED(3f).
o A very special behavior occurs if the keyword name ends in ::. The next parameter is taken as a value even if it starts with -. This is not generally recommended but is noted here for completeness.
o to define a zero-length allocatable array make the value a delimiter (usually a comma).
o all unused values go into the character array UNNAMED
o If the prototype ends with "--" a special mode is turned on where anything after "--" on input goes into the variable REMAINING and the array ARGS instead of becoming elements in the UNNAMED array. This is not needed for normal processing.
When invoking the program line note that (subject to change) the following variations from other common command-line parsers:
o Long names should be all lowercase and always more than one character.
o values for duplicate keywords are appended together with a space separator when a command line is executed.
o numeric keywords are not allowed; but this allows negative numbers to be used as values.
o Although not generally recommended you can equivalence keywords (usually for multi-lingual support). Be aware that specifying both names of an equivalenced keyword on a command line will have undefined results (currently, their ASCII alphabetical order will define what the Fortran variable values become).
The second of the names should only be called with a GET_ARGS*(3f) routine if the SPECIFIED(3f) function is .TRUE. for that name.
Note that allocatable arrays cannot be EQUIVALENCEd in Fortran.
o short keywords cannot be combined unless they were defined using the –LONGNAME:SHORTNAME syntax. Even then -a -b -c is required not -abc unless all the keywords are logicals (Boolean keys).
o shuffling is not supported. Values should follow their keywords.
o if a parameter value of just "-" is supplied it is converted to the string "stdin".
o values not matching a keyword go into the character array "UNUSED".
o if the keyword "--" is encountered the rest of the command arguments go into the character array "UNUSED".
Sample program:
program demo_set_args
use M_CLI2, only : filenames=>unnamed, set_args, get_args
use M_CLI2, only : get_args_fixed_size
implicit none
integer :: i
! DEFINE ARGS
real :: x, y, z
real :: p(3)
character(len=:),allocatable :: title
logical :: l, lbig
integer,allocatable :: ints(:)
!
! DEFINE COMMAND (TO SET INITIAL VALUES AND ALLOWED KEYWORDS)
! AND READ COMMAND LINE
call set_args(' &
! reals
& -x 1 -y 2.3 -z 3.4e2 &
! integer array
& -p -1,-2,-3 &
! always double-quote strings
& --title "my title" &
! set all logical values to F or T.
& -l F -L F &
! set allocatable size to zero if you like by using a delimiter
& -ints , &
! string should be a single character at a minimum
& --label " " &
& ')
! ASSIGN VALUES TO ELEMENTS
! SCALARS
call get_args('x',x)
call get_args('y',y)
call get_args('z',z)
call get_args('l',l)
call get_args('L',lbig)
call get_args('ints',ints) ! ALLOCATABLE ARRAY
call get_args('title',title) ! ALLOCATABLE STRING
call get_args_fixed_size('p',p) ! NON-ALLOCATABLE ARRAY
! USE VALUES
write(*,*)'x=',x
write(*,*)'y=',y
write(*,*)'z=',z
write(*,*)'p=',p
write(*,*)'title=',title
write(*,*)'ints=',ints
write(*,*)'l=',l
write(*,*)'L=',lbig
! UNNAMED VALUES
if(size(filenames).gt.0)then
write(*,'(i6.6,3a)')(i,'[',filenames(i),']',i=1,size(filenames))
endif
end program demo_set_args
If you have no interest in using external files as abbreviations you can ignore this section. Otherwise, before calling set_args(3f) add:
use M_CLI2, only : CLI_response_file CLI_response_file=.true.
M_CLI2 Response files are small files containing CLI (Command Line Interface) arguments that end with ".rsp" that can be used when command lines are so long that they would exceed line length limits or so complex that it is useful to have a platform-independent method of creating an abbreviation.
Shell aliases and scripts are often used for similar purposes (and allow for much more complex conditional execution, of course), but they generally cannot be used to overcome line length limits and are typically platform-specific.
Examples of commands that support similar response files are the Clang and Intel compilers, although there is no standard format for the files.
They are read if you add options of the syntax "@NAME" as the FIRST parameters on your program command line calls. They are not recursive – that is, an option in a response file cannot be given the value "@NAME2" to call another response file.
Note that more than one response name may appear on a command line.
They are case-sensitive names.
LOCATING RESPONSE FILES
A search for the response file always starts with the current directory. The search then proceeds to look in any additional directories specified with the colon-delimited environment variable CLI_RESPONSE_PATH.
The first resource file found that results in lines being processed will be used and processing stops after that first match is found. If no match is found an error occurs and the program is stopped.
RESPONSE FILE SECTIONS
A simple response file just has options for calling the program in it prefixed with the word "options". But they can also contain section headers to denote selections that are only executed when a specific OS is being used, print messages, and execute system commands.
SEARCHING FOR OSTYPE IN REGULAR FILES
So assuming the name @NAME was specified on the command line a file named NAME.rsp will be searched for in all the search directories and then in that file a string that starts with the string @OSTYPE (if the environment variables $OS and $OSTYPE are not blank. $OSTYPE takes precedence over $OS).
SEARCHING FOR UNLABELED DIRECTIVES IN REGULAR FILES
Then, the same files will be searched for lines above any line starting with "@". That is, if there is no special section for the current OS it just looks at the top of the file for unlabeled options.
SEARCHING FOR OSTYPE AND NAME IN THE COMPOUND FILE
In addition or instead of files with the same name as the @NAME option on the command line, you can have one file named after the executable name that contains multiple abbreviation names.
So if your program executable is named EXEC you create a single file called EXEC.rsp and can append all the simple files described above separating them with lines of the form @OSTYPE@NAME or just @NAME.
So if no specific file for the abbreviation is found a file called "EXEC.rsp" is searched for where "EXEC" is the name of the executable. This file is always a "compound" response file that uses the following format:
Any compound EXEC.rsp file found in the current or searched directories will be searched for the string @OSTYPE@NAME first.
Then if nothing is found, the less specific line @NAME is searched for.
THE SEARCH IS OVER
Sounds complicated but actually works quite intuitively. Make a file in the current directory and put options in it and it will be used. If that file ends up needing different cases for different platforms add a line like "@Linux" to the file and some more lines and that will only be executed if the environment variable OSTYPE or OS is "Linux". If no match is found for named sections the lines at the top before any "@" lines will be used as a default if no match is found.
If you end up using a lot of files like this you can combine them all together and put them into a file called "program_name".rsp and just put lines like @NAME or @OSTYPE@NAME at that top of each selection.
Now, back to the details on just what you can put in the files.
SIMPLE RESPONSE FILES
The first word of a line is special and has the following meanings:
options|- Command options following the rules of the SET_ARGS(3f) prototype. So o It is preferred to specify a value for all options. o double-quote strings. o give a blank string value as " ". o use F|T for lists of logicals, o lists of numbers should be comma-delimited. comment|# Line is a comment line system|! System command. System commands are executed as a simple call to system (so a cd(1) or setting a shell variable would not effect subsequent lines, for example) print|> Message to screen stop display message and stop program.
So if a program that does nothing but echos its parameters
program testit use M_CLI2, only : set_args, rget, sget, lget use M_CLI2, only : CLI_response_file implicit none real :: x,y ; namelist/args/ x,y character(len=:),allocatable :: title ; namelist/args/ title logical :: big ; namelist/args/ big CLI_response_file=.true. call set_args('-x 10.0 -y 20.0 –title "my title" –big F') x=rget('x') y=rget('y') title=sget('title') big=lget('big') write(*,nml=args) end program testit
And a file in the current directory called "a.rsp" contains
options -x 1000 -y 9999 options –title " " options –big T
The program could be called with
$myprog # normal call X=10.0 Y=20.0 TITLE="my title"
$myprog # change defaults as specified in "a.rsp" X=1000.0 Y=9999.0 TITLE=" "
$myprog -y 1234 X=1000.0 Y=1234.0 TITLE=" "
COMPOUND RESPONSE FILES
A compound response file has the same basename as the executable with a ".rsp" suffix added. So if your program is named "myprg" the filename must be "myprg.rsp".
Note that here basename means the last leaf of the name of the program as returned by the Fortran intrinsic GET_COMMAND_ARGUMENT(0,...) trimmed of anything after a period ("."), so it is a good idea not to use hidden files.
Unlike simple response files compound response files can contain multiple setting names.
Specifically in a compound file if the environment variable $OSTYPE (first) or $OS is set the first search will be for a line of the form (no leading spaces should be used):
@OSTYPE@alias_name
If no match or if the environment variables $OSTYPE and $OS were not set or a match is not found then a line of the form
@alias_name
is searched for in simple or compound files. If found subsequent lines will be ignored that start with "@" until a line not starting with "@" is encountered. Lines will then be processed until another line starting with "@" is found or end-of-file is encountered.
COMPOUND RESPONSE FILE EXAMPLE An example compound file
> RUNNING TESTS USING RELEASE VERSION AND ifort options test –release –compiler ifort
@gf > RUNNING TESTS USING RELEASE VERSION AND gfortran options test –release –compiler gfortran
@nv > RUNNING TESTS USING RELEASE VERSION AND nvfortran options test –release –compiler nvfortran
@nag > RUNNING TESTS USING RELEASE VERSION AND nagfor options test –release –compiler nagfor #
@Linux@install #
# system mkdir -p ~/.local/bin options run –release T –compiler gfortran –runner "install -vbp -m 0711 -t ~/.local/bin" @install STOP INSTALL NOT SUPPORTED ON THIS PLATFORM OR $OSTYPE NOT SET #
@fpm@testall # !fpm test –compiler nvfortran !fpm test –compiler ifort !fpm test –compiler gfortran !fpm test –compiler nagfor STOP tests complete. Any additional parameters were ignored
Would be used like
fpm @install fpm @nag – fpm @testall
NOTES
The intel Fortran compiler now calls the response files "indirect files" and does not add the implied suffix ".rsp" to the files anymore. It also allows the @NAME syntax anywhere on the command line, not just at the beginning. – 20201212
John S. Urban, 2019
Public Domain
References args, check_commandline(), cli_response_file, debug_m_cli2, g_append, g_options_only, g_passed_in, g_quiet, g_response, g_response_ignored, g_stop, g_stop_message, gen, longest_command_argument(), prototype_and_cmd_args_to_nlist(), split(), unnamed, and wipe_dictionary().

|
private |
|
private |
References unnamed.
| character(len=:) function, allocatable, public m_cli2::sget | ( | character(len=*), intent(in) | n | ) |
|
private |
| elemental impure logical function, public m_cli2::specified | ( | character(len=*), intent(in) | key | ) |
specified(3f) - [ARGUMENTS:M_CLI2] return true if keyword was present on command line (LICENSE:PD)
elemental impure function specified(name) character(len=*),intent(in) :: name logical :: specified
specified(3f) returns .true. if the specified keyword was present on the command line.
NAME name of commandline argument to query the presence of
SPECIFIED returns .TRUE. if specified NAME was present on the command line when the program was invoked.
Sample program:
program demo_specified use M_CLI2, only : set_args, get_args, specified implicit none ! DEFINE ARGS integer :: flag integer,allocatable :: ints(:) real,allocatable :: twonames(:)
! IT IS A BAD IDEA TO NOT HAVE THE SAME DEFAULT VALUE FOR ALIASED ! NAMES BUT CURRENTLY YOU STILL SPECIFY THEM call set_args(' -flag 1 -f 1 -ints 1,2,3 -i 1,2,3 -twonames 11.3 -T 11.3')
! ASSIGN VALUES TO ELEMENTS CONDITIONALLY CALLING WITH SHORT NAME call get_args('flag',flag) if(specified('f'))call get_args('f',flag) call get_args('ints',ints) if(specified('i'))call get_args('i',ints) call get_args('twonames',twonames) if(specified('T'))call get_args('T',twonames)
! IF YOU WANT TO KNOW IF GROUPS OF PARAMETERS WERE SPECIFIED USE ! ANY(3f) and ALL(3f) write(*,*)specified(['twonames','T ']) write(*,*)'ANY:',any(specified(['twonames','T '])) write(*,*)'ALL:',all(specified(['twonames','T ']))
! FOR MUTUALLY EXCLUSIVE if (all(specified(['twonames','T '])))then write(*,*)'You specified both names -T and -twonames' endif
! FOR REQUIRED PARAMETER if (.not.any(specified(['twonames','T '])))then write(*,*)'You must specify -T or -twonames' endif
! USE VALUES write(*,*)'flag=',flag write(*,*)'ints=',ints write(*,*)'twonames=',twonames end program demo_specified
John S. Urban, 2019
Public Domain
References locate_key(), and present_in.

|
private |
split(3f) - [M_CLI2:TOKENS] parse string into an array using specified delimiters (LICENSE:PD)
subroutine split(input_line,array,delimiters,order,nulls) character(len=*),intent(in) :: input_line character(len=:),allocatable,intent(out) :: array(:) character(len=*),optional,intent(in) :: delimiters character(len=*),optional,intent(in) :: order character(len=*),optional,intent(in) :: nulls
SPLIT(3f) parses a string using specified delimiter characters and store tokens into an allocatable array
INPUT_LINE Input string to tokenize
ARRAY Output array of tokens
DELIMITERS List of delimiter characters.
The default delimiters are the "whitespace" characters
(space, tab,new line, vertical tab, formfeed, carriage
return, and null). You may specify an alternate set of
delimiter characters.
Multi-character delimiters are not supported (Each
character in the DELIMITERS list is considered to be
a delimiter).
Quoting of delimiter characters is not supported.
ORDER SEQUENTIAL|REVERSE|RIGHT Order of output array.
By default ARRAY contains the tokens having parsed
the INPUT_LINE from left to right. If ORDER='RIGHT'
or ORDER='REVERSE' the parsing goes from right to left.
NULLS IGNORE|RETURN|IGNOREEND Treatment of null fields.
By default adjacent delimiters in the input string
do not create an empty string in the output array. if
NULLS='return' adjacent delimiters create an empty element
in the output ARRAY. If NULLS='ignoreend' then only
trailing delimiters at the right of the string are ignored.
Sample program:
program demo_split
use M_CLI2, only: split
character(len=*),parameter :: &
& line=' aBcdef ghijklmnop qrstuvwxyz 1:|:2 333|333 a B cc '
character(len=:),allocatable :: array(:) ! output array of tokens
write(*,*)'INPUT LINE:['//LINE//']'
write(*,'(80("="))')
write(*,*)'typical call:'
CALL split(line,array)
write(*,'(i0," ==> ",a)')(i,trim(array(i)),i=1,size(array))
write(*,*)'SIZE:',SIZE(array)
write(*,'(80("-"))')
write(*,*)'custom list of delimiters (colon and vertical line):'
CALL split(line,array,delimiters=':|',order='sequential',nulls='ignore')
write(*,'(i0," ==> ",a)')(i,trim(array(i)),i=1,size(array))
write(*,*)'SIZE:',SIZE(array)
write(*,'(80("-"))')
write(*,*)&
&'custom list of delimiters, reverse array order and count null fields:'
CALL split(line,array,delimiters=':|',order='reverse',nulls='return')
write(*,'(i0," ==> ",a)')(i,trim(array(i)),i=1,size(array))
write(*,*)'SIZE:',SIZE(array)
write(*,'(80("-"))')
write(*,*)'INPUT LINE:['//LINE//']'
write(*,*)&
&'default delimiters and reverse array order and return null fields:'
CALL split(line,array,delimiters='',order='reverse',nulls='return')
write(*,'(i0," ==> ",a)')(i,trim(array(i)),i=1,size(array))
write(*,*)'SIZE:',SIZE(array)
end program demo_split
Output
> INPUT LINE:[ aBcdef ghijklmnop qrstuvwxyz 1:|:2 333|333 a B cc ] > =========================================================================== > typical call: > 1 ==> aBcdef > 2 ==> ghijklmnop > 3 ==> qrstuvwxyz > 4 ==> 1:|:2 > 5 ==> 333|333 > 6 ==> a > 7 ==> B > 8 ==> cc > SIZE: 8 > -----------------------------------------------------------------------— > custom list of delimiters (colon and vertical line): > 1 ==> aBcdef ghijklmnop qrstuvwxyz 1 > 2 ==> 2 333 > 3 ==> 333 a B cc > SIZE: 3 > -----------------------------------------------------------------------— > custom list of delimiters, reverse array order and return null fields: > 1 ==> 333 a B cc > 2 ==> 2 333 > 3 ==> > 4 ==> > 5 ==> aBcdef ghijklmnop qrstuvwxyz 1 > SIZE: 5 > -----------------------------------------------------------------------— > INPUT LINE:[ aBcdef ghijklmnop qrstuvwxyz 1:|:2 333|333 a B cc ] > default delimiters and reverse array order and count null fields: > 1 ==> > 2 ==> > 3 ==> > 4 ==> cc > 5 ==> B > 6 ==> a > 7 ==> 333|333 > 8 ==> > 9 ==> > 10 ==> > 11 ==> > 12 ==> 1:|:2 > 13 ==> > 14 ==> qrstuvwxyz > 15 ==> ghijklmnop > 16 ==> > 17 ==> > 18 ==> aBcdef > 19 ==> > 20 ==> > SIZE: 20
John S. Urban
Public Domain
References lower().


|
private |

|
private |
substitute(3f) - [M_CLI2:EDITING] subroutine globally substitutes one substring for another in string (LICENSE:PD)
subroutine substitute(targetline,old,new,ierr,start,end) character(len=*) :: targetline character(len=*),intent(in) :: old character(len=*),intent(in) :: new integer,intent(out),optional :: ierr integer,intent(in),optional :: start integer,intent(in),optional :: end
Globally substitute one substring for another in string.
TARGETLINE input line to be changed. Must be long enough to hold altered output. OLD substring to find and replace NEW replacement for OLD substring IERR error code. If IER = -1 bad directive, >= 0 then count of changes made. START sets the left margin to be scanned for OLD in TARGETLINE. END sets the right margin to be scanned for OLD in TARGETLINE.
Sample Program:
program demo_substitute use M_CLI2, only : substitute implicit none ! must be long enough to hold changed line character(len=80) :: targetline targetline='this is the input string' write(*,*)'ORIGINAL : '//trim(targetline) ! changes the input to 'THis is THe input string' call substitute(targetline,'th','TH') write(*,*)'th => TH : '//trim(targetline) ! a null old substring means "at beginning of line" ! changes the input to 'BEFORE:this is the input string' call substitute(targetline,'','BEFORE:') write(*,*)'"" => BEFORE: '//trim(targetline) ! a null new string deletes occurrences of the old substring ! changes the input to 'ths s the nput strng' call substitute(targetline,'i','') write(*,*)'i => "" : '//trim(targetline) end program demo_substitute
Expected output
ORIGINAL : this is the input string th => TH : THis is THe input string "" => BEFORE: BEFORE:THis is THe input string i => "" : BEFORE:THs s THe nput strng
John S. Urban
Public Domain
References journal().


|
private |
trimzeros_(3fp) - [M_CLI2:NUMERIC] Delete trailing zeros from numeric decimal string (LICENSE:PD)
subroutine trimzeros_(str) character(len=*) :: str
TRIMZEROS_(3f) deletes trailing zeros from a string representing a number. If the resulting string would end in a decimal point, one trailing zero is added.
str input string will be assumed to be a numeric value and have trailing zeros removed
Sample program:
program demo_trimzeros_
use M_CLI2, only : trimzeros_
character(len=:),allocatable :: string
write(*,*)trimzeros_('123.450000000000')
write(*,*)trimzeros_('12345')
write(*,*)trimzeros_('12345.')
write(*,*)trimzeros_('12345.00e3')
end program demo_trimzeros_
John S. Urban
Public Domain

|
private |
unquote(3f) - [M_CLI2:QUOTES] remove quotes from string as if read with list-directed input (LICENSE:PD)
pure function unquote(quoted_str,esc) result (unquoted_str)
character(len=*),intent(in) :: quoted_str character(len=1),optional,intent(in) :: esc character(len=:),allocatable :: unquoted_str
Remove quotes from a CHARACTER variable as if it was read using list-directed input. This is particularly useful for processing tokens read from input such as CSV files.
Fortran can now read using list-directed input from an internal file, which should handle quoted strings, but list-directed input does not support escape characters, which UNQUOTE(3f) does.
quoted_str input string to remove quotes from, using the rules of list-directed input (two adjacent quotes inside a quoted region are replaced by a single quote, a single quote or double quote is selected as the delimiter based on which is encountered first going from left to right, ...) esc optional character used to protect the next quote character from being processed as a quote, but simply as a plain character.
unquoted_str The output string, which is based on removing quotes from quoted_str.
Sample program:
program demo_unquote
use M_CLI2, only : unquote
implicit none
character(len=128) :: quoted_str
character(len=:),allocatable :: unquoted_str
character(len=1),parameter :: esc='\'
character(len=1024) :: msg
integer :: ios
character(len=1024) :: dummy
do
write(*,'(a)',advance='no')'Enter test string:'
read(*,'(a)',iostat=ios,iomsg=msg)quoted_str
if(ios.ne.0)then
write(*,*)trim(msg)
exit
endif
! the original string
write(*,'(a)')'QUOTED ['//trim(quoted_str)//']'
! the string processed by unquote(3f)
unquoted_str=unquote(trim(quoted_str),esc)
write(*,'(a)')'UNQUOTED ['//unquoted_str//']'
! read the string list-directed to compare the results
read(quoted_str,*,iostat=ios,iomsg=msg)dummy
if(ios.ne.0)then
write(*,*)trim(msg)
else
write(*,'(a)')'LIST DIRECTED['//trim(dummy)//']'
endif
enddo
end program demo_unquote
John S. Urban
Public Domain
References quote().


|
private |
update(3f) - [ARGUMENTS:M_CLI2] update internal dictionary given keyword and value (LICENSE:PD)
subroutine update(key,val) character(len=*),intent(in) :: key character(len=*),intent(in),optional :: val
Update internal dictionary in M_CLI2(3fm) module.
key name of keyword to add, replace, or delete from dictionary val if present add or replace value associated with keyword. If not present remove keyword entry from dictionary.
If "present" is true, a value will be appended
John S. Urban, 2019
Public Domain
References counts, g_append, g_strict, keywords, locate_key(), mandatory, present_in, shorts, split(), unquote(), and values.


|
private |

|
private |
value_to_string(3f) - [M_CLI2:NUMERIC] return numeric string from a numeric value (LICENSE:PD)
subroutine value_to_string(value,chars[,iilen,ierr,fmt,trimz]) character(len=*) :: chars ! minimum of 23 characters required !-------- ! VALUE may be any <em>one</em> of the following types: doubleprecision,intent(in) :: value real,intent(in) :: value integer,intent(in) :: value logical,intent(in) :: value !-------- character(len=*),intent(out) :: chars integer,intent(out),optional :: iilen integer,optional :: ierr character(len=*),intent(in),optional :: fmt logical,intent(in) :: trimz
value_to_string(3f) returns a numeric representation of a numeric value in a string given a numeric value of type REAL, DOUBLEPRECISION, INTEGER or LOGICAL. It creates the string using internal writes. It then removes trailing zeros from non-zero values, and left-justifies the string.
VALUE input value to be converted to a string FMT You may specify a specific format that produces a string up to the length of CHARS; optional. TRIMZ If a format is supplied the default is not to try to trim trailing zeros. Set TRIMZ to .true. to trim zeros from a string assumed to represent a simple numeric value.
CHARS returned string representing input value, must be at least 23 characters long; or what is required by optional FMT if longer. IILEN position of last non-blank character in returned string; optional. IERR If not zero, error occurred; optional.
Sample program:
program demo_value_to_string
use M_CLI2, only: value_to_string
implicit none
character(len=80) :: string
integer :: iilen
call value_to_string(3.0/4.0,string,iilen)
write(*,*) 'The value is [',string(:iilen),']'
call value_to_string(3.0/4.0,string,iilen,fmt='')
write(*,*) 'The value is [',string(:iilen),']'
call value_to_string(3.0/4.0,string,iilen,fmt='("THE VALUE IS ",g0)')
write(*,*) 'The value is [',string(:iilen),']'
call value_to_string(1234,string,iilen)
write(*,*) 'The value is [',string(:iilen),']'
call value_to_string(1.0d0/3.0d0,string,iilen)
write(*,*) 'The value is [',string(:iilen),']'
end program demo_value_to_string
Expected output
The value is [0.75] The value is [ 0.7500000000] The value is [THE VALUE IS .750000000] The value is [1234] The value is [0.33333333333333331]
John S. Urban
Public Domain
References journal(), and trimzeros_().


|
private |
wipe_dictionary(3fp) - [ARGUMENTS:M_CLI2] reset private M_CLI2(3fm) dictionary to empty (LICENSE:PD)
subroutine wipe_dictionary()
reset private M_CLI2(3fm) dictionary to empty
Sample program:
program demo_wipe_dictionary
use M_CLI2, only : dictionary
call wipe_dictionary()
end program demo_wipe_dictionary
John S. Urban, 2019
Public Domain
References counts, keywords, mandatory, present_in, shorts, and values.

| character(len=:), dimension(:), allocatable, public m_cli2::args |
| logical, save, public m_cli2::cli_response_file =.false. |
|
private |
| logical, save, public m_cli2::debug_m_cli2 =.false. |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
| character(len=:), allocatable, public m_cli2::remaining |
|
private |
|
private |
| character(len=:), dimension(:), allocatable, public m_cli2::unnamed |
|
private |
1.8.17