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 |