!|author: Rich Townsend
! license: LGPL
! iso_varying_string.f90
!
! Copyright (C) 2003 Rich Townsend
!
! This program is free software; you can redistribute it and/or
! modify it under the terms of the GNU Lesser General Public
! License as published by the Free Software Foundation; either
! version 2.1 of the License, or (at your option) any later
! version.
!
! This program is distributed in the hope that it will be
! useful, but WITHOUT ANY WARRANTY; without even the implied
! warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
! PURPOSE. See the GNU Lesser General Public License for more
! details.
!
! You should have received a copy of the GNU Lesser General
! Public License along with this program; if not, write to the
! Free Software Foundation, Inc., 59 Temple Place, Suite 330,
! Boston, MA 02111-1307 USA
!
! *****************************************************************
!
! Developer : Rich Townsend
!
! Synopsis : Definition of iso_varying_string module, conformant to
! the API specified in ISO/IEC 1539-2:2000 (varying-length
! strings for Fortran 95).
!
! Notes : This implementation of iso_varying_string is designed to avoid
! the possibility of memory leaks. To achieve this, it takes
! advantage of language extensions specified in ISO/IEC
! TR 15581 (enhanced data type facilities). Many vendors
! support these extensions, and they will form a core part
! of Fortran 2000.
!
! Version : 1.2
!
! Thanks : Lawrie Schonfelder's iso_varying_string module provided me
! with much insight on how to go about writing this module,
! for which I am very grateful. Furthermore, Lawrie helped
! point out some subtle bugs in the module.
!
module iso_varying_string
! No implicit typing
implicit none
! Parameter definitions
integer, parameter :: GET_BUFFER_LEN = 256
! Type definitions
type varying_string
private
character(LEN=1), dimension(:), allocatable :: chars
end type varying_string
! Interface blocks
interface assignment(=)
module procedure op_assign_CH_VS
module procedure op_assign_VS_CH
end interface assignment(=)
interface operator(//)
module procedure op_concat_VS_VS
module procedure op_concat_CH_VS
module procedure op_concat_VS_CH
end interface operator(//)
interface operator(==)
module procedure op_eq_VS_VS
module procedure op_eq_CH_VS
module procedure op_eq_VS_CH
end interface operator(==)
interface operator(/=)
module procedure op_ne_VS_VS
module procedure op_ne_CH_VS
module procedure op_ne_VS_CH
end interface operator (/=)
interface operator(<)
module procedure op_lt_VS_VS
module procedure op_lt_CH_VS
module procedure op_lt_VS_CH
end interface operator (<)
interface operator(<=)
module procedure op_le_VS_VS
module procedure op_le_CH_VS
module procedure op_le_VS_CH
end interface operator (<=)
interface operator(>=)
module procedure op_ge_VS_VS
module procedure op_ge_CH_VS
module procedure op_ge_VS_CH
end interface operator (>=)
interface operator(>)
module procedure op_gt_VS_VS
module procedure op_gt_CH_VS
module procedure op_gt_VS_CH
end interface operator (>)
interface adjustl
module procedure adjustl_
end interface adjustl
interface adjustr
module procedure adjustr_
end interface adjustr
interface char
module procedure char_auto
module procedure char_fixed
end interface char
interface iachar
module procedure iachar_
end interface iachar
interface ichar
module procedure ichar_
end interface ichar
interface index
module procedure index_VS_VS
module procedure index_CH_VS
module procedure index_VS_CH
end interface index
interface len
module procedure len_
end interface len
interface len_trim
module procedure len_trim_
end interface len_trim
interface lge
module procedure lge_VS_VS
module procedure lge_CH_VS
module procedure lge_VS_CH
end interface lge
interface lgt
module procedure lgt_VS_VS
module procedure lgt_CH_VS
module procedure lgt_VS_CH
end interface lgt
interface lle
module procedure lle_VS_VS
module procedure lle_CH_VS
module procedure lle_VS_CH
end interface lle
interface llt
module procedure llt_VS_VS
module procedure llt_CH_VS
module procedure llt_VS_CH
end interface llt
interface repeat
module procedure repeat_
end interface repeat
interface scan
module procedure scan_VS_VS
module procedure scan_CH_VS
module procedure scan_VS_CH
end interface scan
interface trim
module procedure trim_
end interface trim
interface verify
module procedure verify_VS_VS
module procedure verify_CH_VS
module procedure verify_VS_CH
end interface verify
interface var_str
module procedure var_str_
end interface var_str
interface get
module procedure get_
module procedure get_unit
module procedure get_set_VS
module procedure get_set_CH
module procedure get_unit_set_VS
module procedure get_unit_set_CH
end interface get
interface put
module procedure put_VS
module procedure put_CH
module procedure put_unit_VS
module procedure put_unit_CH
end interface put
interface put_line
module procedure put_line_VS
module procedure put_line_CH
module procedure put_line_unit_VS
module procedure put_line_unit_CH
end interface put_line
interface extract
module procedure extract_VS
module procedure extract_CH
end interface extract
interface insert
module procedure insert_VS_VS
module procedure insert_CH_VS
module procedure insert_VS_CH
module procedure insert_CH_CH
end interface insert
interface remove
module procedure remove_VS
module procedure remove_CH
end interface remove
interface replace
module procedure replace_VS_VS_auto
module procedure replace_CH_VS_auto
module procedure replace_VS_CH_auto
module procedure replace_CH_CH_auto
module procedure replace_VS_VS_fixed
module procedure replace_CH_VS_fixed
module procedure replace_VS_CH_fixed
module procedure replace_CH_CH_fixed
module procedure replace_VS_VS_VS_target
module procedure replace_CH_VS_VS_target
module procedure replace_VS_CH_VS_target
module procedure replace_CH_CH_VS_target
module procedure replace_VS_VS_CH_target
module procedure replace_CH_VS_CH_target
module procedure replace_VS_CH_CH_target
module procedure replace_CH_CH_CH_target
end interface
interface split
module procedure split_VS
module procedure split_CH
end interface split
! Access specifiers
private
public :: varying_string
public :: assignment(=)
public :: operator(//)
public :: operator(==)
public :: operator(/=)
public :: operator(<)
public :: operator(<=)
public :: operator(>=)
public :: operator(>)
public :: adjustl
public :: adjustr
public :: char
public :: iachar
public :: ichar
public :: index
public :: len
public :: len_trim
public :: lge
public :: lgt
public :: lle
public :: llt
public :: repeat
public :: scan
public :: trim
public :: verify
public :: var_str
public :: get
public :: put
public :: put_line
public :: extract
public :: insert
public :: remove
public :: replace
public :: split
! Procedures
contains
!| Assign a varying string to a character string
elemental subroutine op_assign_CH_VS (var, exp)
character(LEN=*), intent(out) :: var
type(varying_string), intent(in) :: exp
var = char(exp)
! Finish
return
end subroutine op_assign_CH_VS
!| Assign a character string to a varying string
!
elemental subroutine op_assign_VS_CH (var, exp)
type(varying_string), intent(out) :: var
character(LEN=*), intent(in) :: exp
var = var_str(exp)
! Finish
return
end subroutine op_assign_VS_CH
!| Concatenate two varying strings
!
elemental function op_concat_VS_VS (string_a, string_b) result (concat_string)
type(varying_string), intent(in) :: string_a
type(varying_string), intent(in) :: string_b
type(varying_string) :: concat_string
integer :: len_string_a
len_string_a = len(string_a)
ALLOCATE(concat_string%chars(len_string_a+len(string_b)))
concat_string%chars(:len_string_a) = string_a%chars
concat_string%chars(len_string_a+1:) = string_b%chars
! Finish
return
end function op_concat_VS_VS
!| Concatenate a character string and a varying
! string
!
elemental function op_concat_CH_VS (string_a, string_b) result (concat_string)
character(LEN=*), intent(in) :: string_a
type(varying_string), intent(in) :: string_b
type(varying_string) :: concat_string
concat_string = op_concat_VS_VS(var_str(string_a), string_b)
! Finish
return
end function op_concat_CH_VS
!| Concatenate a varying string and a character
! string
elemental function op_concat_VS_CH (string_a, string_b) result (concat_string)
type(varying_string), intent(in) :: string_a
character(LEN=*), intent(in) :: string_b
type(varying_string) :: concat_string
concat_string = op_concat_VS_VS(string_a, var_str(string_b))
! Finish
return
end function op_concat_VS_CH
!| Compare (==) two varying strings
!
elemental function op_eq_VS_VS (string_a, string_b) result (op_eq)
type(varying_string), intent(in) :: string_a
type(varying_string), intent(in) :: string_b
logical :: op_eq
op_eq = char(string_a) == char(string_b)
! Finish
return
end function op_eq_VS_VS
!| Compare (==) a character string and a varying
! string
!
elemental function op_eq_CH_VS (string_a, string_b) result (op_eq)
character(LEN=*), intent(in) :: string_a
type(varying_string), intent(in) :: string_b
logical :: op_eq
op_eq = string_a == char(string_b)
! Finish
return
end function op_eq_CH_VS
!| Compare (==) a varying string and a character string
!
elemental function op_eq_VS_CH (string_a, string_b) result (op_eq)
type(varying_string), intent(in) :: string_a
character(LEN=*), intent(in) :: string_b
logical :: op_eq
op_eq = char(string_a) == string_b
! Finish
return
end function op_eq_VS_CH
!| Compare (/=) two varying strings
!
elemental function op_ne_VS_VS (string_a, string_b) result (op_ne)
type(varying_string), intent(in) :: string_a
type(varying_string), intent(in) :: string_b
logical :: op_ne
op_ne = char(string_a) /= char(string_b)
! Finish
return
end function op_ne_VS_VS
!| Compare (/=) a character string and a varying string
!
elemental function op_ne_CH_VS (string_a, string_b) result (op_ne)
character(LEN=*), intent(in) :: string_a
type(varying_string), intent(in) :: string_b
logical :: op_ne
op_ne = string_a /= char(string_b)
! Finish
return
end function op_ne_CH_VS
!| Compare (/=) a varying string and a character string
!
elemental function op_ne_VS_CH (string_a, string_b) result (op_ne)
type(varying_string), intent(in) :: string_a
character(LEN=*), intent(in) :: string_b
logical :: op_ne
op_ne = char(string_a) /= string_b
! Finish
return
end function op_ne_VS_CH
!| Compare (<) two varying strings
!
elemental function op_lt_VS_VS (string_a, string_b) result (op_lt)
type(varying_string), intent(in) :: string_a
type(varying_string), intent(in) :: string_b
logical :: op_lt
op_lt = char(string_a) < char(string_b)
! Finish
return
end function op_lt_VS_VS
!| Compare (<) a character string and a varying string
!
elemental function op_lt_CH_VS (string_a, string_b) result (op_lt)
character(LEN=*), intent(in) :: string_a
type(varying_string), intent(in) :: string_b
logical :: op_lt
op_lt = string_a < char(string_b)
! Finish
return
end function op_lt_CH_VS
!| Compare (<) a varying string and a character string
!
elemental function op_lt_VS_CH (string_a, string_b) result (op_lt)
type(varying_string), intent(in) :: string_a
character(LEN=*), intent(in) :: string_b
logical :: op_lt
op_lt = char(string_a) < string_b
! Finish
return
end function op_lt_VS_CH
!| Compare (<=) two varying strings
!
elemental function op_le_VS_VS (string_a, string_b) result (op_le)
type(varying_string), intent(in) :: string_a
type(varying_string), intent(in) :: string_b
logical :: op_le
op_le = char(string_a) <= char(string_b)
! Finish
return
end function op_le_VS_VS
!| Compare (<=) a character string and a varying string
!
elemental function op_le_CH_VS (string_a, string_b) result (op_le)
character(LEN=*), intent(in) :: string_a
type(varying_string), intent(in) :: string_b
logical :: op_le
op_le = string_a <= char(string_b)
! Finish
return
end function op_le_CH_VS
!| Compare (<=) a varying string and a character string
!
elemental function op_le_VS_CH (string_a, string_b) result (op_le)
type(varying_string), intent(in) :: string_a
character(LEN=*), intent(in) :: string_b
logical :: op_le
op_le = char(string_a) <= string_b
! Finish
return
end function op_le_VS_CH
!| Compare (>=) two varying strings
!
elemental function op_ge_VS_VS (string_a, string_b) result (op_ge)
type(varying_string), intent(in) :: string_a
type(varying_string), intent(in) :: string_b
logical :: op_ge
op_ge = char(string_a) >= char(string_b)
! Finish
return
end function op_ge_VS_VS
!| Compare (>=) a character string and a varying string
!
elemental function op_ge_CH_VS (string_a, string_b) result (op_ge)
character(LEN=*), intent(in) :: string_a
type(varying_string), intent(in) :: string_b
logical :: op_ge
op_ge = string_a >= char(string_b)
! Finish
return
end function op_ge_CH_VS
!| Compare (>=) a varying string and a character string
!
elemental function op_ge_VS_CH (string_a, string_b) result (op_ge)
type(varying_string), intent(in) :: string_a
character(LEN=*), intent(in) :: string_b
logical :: op_ge
op_ge = char(string_a) >= string_b
! Finish
return
end function op_ge_VS_CH
!| Compare (>) two varying strings
!
elemental function op_gt_VS_VS (string_a, string_b) result (op_gt)
type(varying_string), intent(in) :: string_a
type(varying_string), intent(in) :: string_b
logical :: op_gt
op_gt = char(string_a) > char(string_b)
! Finish
return
end function op_gt_VS_VS
!| Compare (>) a character string and a varying string
!
elemental function op_gt_CH_VS (string_a, string_b) result (op_gt)
character(LEN=*), intent(in) :: string_a
type(varying_string), intent(in) :: string_b
logical :: op_gt
op_gt = string_a > char(string_b)
! Finish
return
end function op_gt_CH_VS
!| Compare (>) a varying string and a character string
!
elemental function op_gt_VS_CH (string_a, string_b) result (op_gt)
type(varying_string), intent(in) :: string_a
character(LEN=*), intent(in) :: string_b
logical :: op_gt
op_gt = char(string_a) > string_b
! Finish
return
end function op_gt_VS_CH
!| Adjust the varying string to the left
!
elemental function adjustl_ (string) result (adjustl_string)
type(varying_string), intent(in) :: string
type(varying_string) :: adjustl_string
adjustl_string = ADJUSTL(CHAR(string))
! Finish
return
end function adjustl_
!| Adjust the varying string to the right
!
elemental function adjustr_ (string) result (adjustr_string)
type(varying_string), intent(in) :: string
type(varying_string) :: adjustr_string
adjustr_string = ADJUSTR(CHAR(string))
! Finish
return
end function adjustr_
!| Convert a varying string into a character string
! (automatic length)
!
pure function char_auto (string) result (char_string)
type(varying_string), intent(in) :: string
character(LEN=len(string)) :: char_string
integer :: i_char
forall(i_char = 1:len(string))
char_string(i_char:i_char) = string%chars(i_char)
end forall
! Finish
return
end function char_auto
!| Convert a varying string into a character string
! (fixed length)
pure function char_fixed (string, length) result (char_string)
type(varying_string), intent(in) :: string
integer, intent(in) :: length
character(LEN=length) :: char_string
char_string = char(string)
! Finish
return
end function char_fixed
!| Get the position in the ISO 646 collating sequence
! of a varying string character
!
elemental function iachar_ (c) result (i)
type(varying_string), intent(in) :: c
integer :: i
i = IACHAR(char(c))
! Finish
return
end function iachar_
!| Get the position in the processor collating
! sequence of a varying string character
!
elemental function ichar_ (c) result (i)
type(varying_string), intent(in) :: c
integer :: i
i = ICHAR(char(c))
! Finish
return
end function ichar_
!| Get the index of a varying substring within a
! varying string
!
elemental function index_VS_VS (string, substring, back) result (i_substring)
type(varying_string), intent(in) :: string
type(varying_string), intent(in) :: substring
logical, intent(in), optional :: back
integer :: i_substring
i_substring = INDEX(char(string), char(substring), back)
! Finish
return
end function index_VS_VS
!| Get the index of a varying substring within a
! character string
!
elemental function index_CH_VS (string, substring, back) result (i_substring)
character(LEN=*), intent(in) :: string
type(varying_string), intent(in) :: substring
logical, intent(in), optional :: back
integer :: i_substring
i_substring = INDEX(string, char(substring), back)
! Finish
return
end function index_CH_VS
!| Get the index of a character substring within a
! varying string
!
elemental function index_VS_CH (string, substring, back) result (i_substring)
type(varying_string), intent(in) :: string
character(LEN=*), intent(in) :: substring
logical, intent(in), optional :: back
integer :: i_substring
i_substring = INDEX(char(string), substring, back)
! Finish
return
end function index_VS_CH
!| Get the length of a varying string
!
elemental function len_ (string) result (length)
type(varying_string), intent(in) :: string
integer :: length
if(ALLOCATED(string%chars)) then
length = SIZE(string%chars)
else
length = 0
endif
! Finish
return
end function len_
!| Get the trimmed length of a varying string
!
elemental function len_trim_ (string) result (length)
type(varying_string), intent(in) :: string
integer :: length
if(ALLOCATED(string%chars)) then
length = LEN_TRIM(char(string))
else
length = 0
endif
! Finish
return
end function len_trim_
!| Compare (LGE) two varying strings
!
elemental function lge_VS_VS (string_a, string_b) result (comp)
type(varying_string), intent(in) :: string_a
type(varying_string), intent(in) :: string_b
logical :: comp
comp = LGE(char(string_a), char(string_b))
! Finish
return
end function lge_VS_VS
!| Compare (LGE) a character string and a varying string
!
elemental function lge_CH_VS (string_a, string_b) result (comp)
character(LEN=*), intent(in) :: string_a
type(varying_string), intent(in) :: string_b
logical :: comp
comp = LGE(string_a, char(string_b))
! Finish
return
end function lge_CH_VS
!| Compare (LGE) a varying string and a character string
!
elemental function lge_VS_CH (string_a, string_b) result (comp)
type(varying_string), intent(in) :: string_a
character(LEN=*), intent(in) :: string_b
logical :: comp
comp = LGE(char(string_a), string_b)
! Finish
return
end function lge_VS_CH
!| Compare (LGT) two varying strings
!
elemental function lgt_VS_VS (string_a, string_b) result (comp)
type(varying_string), intent(in) :: string_a
type(varying_string), intent(in) :: string_b
logical :: comp
comp = LGT(char(string_a), char(string_b))
! Finish
return
end function lgt_VS_VS
!| Compare (LGT) a character string and a varying string
!
elemental function lgt_CH_VS (string_a, string_b) result (comp)
character(LEN=*), intent(in) :: string_a
type(varying_string), intent(in) :: string_b
logical :: comp
comp = LGT(string_a, char(string_b))
! Finish
return
end function lgt_CH_VS
!| Compare (LGT) a varying string and a character string
!
elemental function lgt_VS_CH (string_a, string_b) result (comp)
type(varying_string), intent(in) :: string_a
character(LEN=*), intent(in) :: string_b
logical :: comp
comp = LGT(char(string_a), string_b)
! Finish
return
end function lgt_VS_CH
!| Compare (LLE) two varying strings
!
elemental function lle_VS_VS (string_a, string_b) result (comp)
type(varying_string), intent(in) :: string_a
type(varying_string), intent(in) :: string_b
logical :: comp
comp = LLE(char(string_a), char(string_b))
! Finish
return
end function lle_VS_VS
!| Compare (LLE) a character string and a varying string
!
elemental function lle_CH_VS (string_a, string_b) result (comp)
character(LEN=*), intent(in) :: string_a
type(varying_string), intent(in) :: string_b
logical :: comp
comp = LLE(string_a, char(string_b))
! Finish
return
end function lle_CH_VS
!| Compare (LLE) a varying string and a character string
!
elemental function lle_VS_CH (string_a, string_b) result (comp)
type(varying_string), intent(in) :: string_a
character(LEN=*), intent(in) :: string_b
logical :: comp
comp = LLE(char(string_a), string_b)
! Finish
return
end function lle_VS_CH
!| Compare (LLT) two varying strings
!
elemental function llt_VS_VS (string_a, string_b) result (comp)
type(varying_string), intent(in) :: string_a
type(varying_string), intent(in) :: string_b
logical :: comp
comp = LLT(char(string_a), char(string_b))
! Finish
return
end function llt_VS_VS
!| Compare (LLT) a character string and a varying string
!
elemental function llt_CH_VS (string_a, string_b) result (comp)
character(LEN=*), intent(in) :: string_a
type(varying_string), intent(in) :: string_b
logical :: comp
comp = LLT(string_a, char(string_b))
! Finish
return
end function llt_CH_VS
!| Compare (LLT) a varying string and a character string
!
elemental function llt_VS_CH (string_a, string_b) result (comp)
type(varying_string), intent(in) :: string_a
character(LEN=*), intent(in) :: string_b
logical :: comp
comp = LLT(char(string_a), string_b)
! Finish
return
end function llt_VS_CH
!| Concatenate several copies of a varying string
!
elemental function repeat_ (string, ncopies) result (repeat_string)
type(varying_string), intent(in) :: string
integer, intent(in) :: ncopies
type(varying_string) :: repeat_string
repeat_string = var_str(REPEAT(char(string), ncopies))
! Finish
return
end function repeat_
!| Scan a varying string for occurrences of
! characters in a varying-string set
!
elemental function scan_VS_VS (string, set, back) result (i)
type(varying_string), intent(in) :: string
type(varying_string), intent(in) :: set
logical, intent(in), optional :: back
integer :: i
i = SCAN(char(string), char(set), back)
! Finish
return
end function scan_VS_VS
!| Scan a character string for occurrences of
! characters in a varying-string set
!
elemental function scan_CH_VS (string, set, back) result (i)
character(LEN=*), intent(in) :: string
type(varying_string), intent(in) :: set
logical, intent(in), optional :: back
integer :: i
i = SCAN(string, char(set), back)
! Finish
return
end function scan_CH_VS
!| Scan a varying string for occurrences of
! characters in a character-string set
!
elemental function scan_VS_CH (string, set, back) result (i)
type(varying_string), intent(in) :: string
character(LEN=*), intent(in) :: set
logical, intent(in), optional :: back
integer :: i
i = SCAN(char(string), set, back)
! Finish
return
end function scan_VS_CH
!| Remove trailing blanks from a varying string
!
elemental function trim_ (string) result (trim_string)
type(varying_string), intent(in) :: string
type(varying_string) :: trim_string
trim_string = TRIM(char(string))
! Finish
return
end function trim_
!| Verify a varying string for occurrences of
! characters in a varying-string set
!
elemental function verify_VS_VS (string, set, back) result (i)
type(varying_string), intent(in) :: string
type(varying_string), intent(in) :: set
logical, intent(in), optional :: back
integer :: i
i = VERIFY(char(string), char(set), back)
! Finish
return
end function verify_VS_VS
!| Verify a character string for occurrences of
! characters in a varying-string set
!
elemental function verify_CH_VS (string, set, back) result (i)
character(LEN=*), intent(in) :: string
type(varying_string), intent(in) :: set
logical, intent(in), optional :: back
integer :: i
i = VERIFY(string, char(set), back)
! Finish
return
end function verify_CH_VS
!| Verify a varying string for occurrences of
! characters in a character-string set
!
elemental function verify_VS_CH (string, set, back) result (i)
type(varying_string), intent(in) :: string
character(LEN=*), intent(in) :: set
logical, intent(in), optional :: back
integer :: i
i = VERIFY(char(string), set, back)
! Finish
return
end function verify_VS_CH
!| Convert a character string to a varying string
!
elemental function var_str_ (char) result (string)
character(LEN=*), intent(in) :: char
type(varying_string) :: string
integer :: length
integer :: i_char
length = LEN(char)
ALLOCATE(string%chars(length))
forall(i_char = 1:length)
string%chars(i_char) = char(i_char:i_char)
end forall
! Finish
return
end function var_str_
!| Read from the default unit into a varying string
!
subroutine get_ (string, maxlen, iostat)
type(varying_string), intent(out) :: string
integer, intent(in), optional :: maxlen
integer, intent(out), optional :: iostat
integer :: n_chars_remain
integer :: n_chars_read
character(LEN=GET_BUFFER_LEN) :: buffer
string = ''
if(PRESENT(maxlen)) then
n_chars_remain = maxlen
else
n_chars_remain = HUGE(1)
endif
read_loop : do
if(n_chars_remain <= 0) return
n_chars_read = MIN(n_chars_remain, GET_BUFFER_LEN)
if(PRESENT(iostat)) then
read(*, FMT='(A)', ADVANCE='NO', IOSTAT=iostat, SIZE=n_chars_read) buffer(:n_chars_read)
if(iostat < 0) exit read_loop
if(iostat > 0) return
else
read(*, FMT='(A)', ADVANCE='NO', EOR=999, SIZE=n_chars_read) buffer(:n_chars_read)
endif
string = string//buffer(:n_chars_read)
n_chars_remain = n_chars_remain - n_chars_read
end do read_loop
999 continue
string = string//buffer(:n_chars_read)
! Finish (end-of-record)
return
end subroutine get_
!| Read from the specified unit into a varying string
!
subroutine get_unit (unit, string, maxlen, iostat)
integer, intent(in) :: unit
type(varying_string), intent(out) :: string
integer, intent(in), optional :: maxlen
integer, intent(out), optional :: iostat
integer :: n_chars_remain
integer :: n_chars_read
character(LEN=GET_BUFFER_LEN) :: buffer
string = ''
if(PRESENT(maxlen)) then
n_chars_remain = maxlen
else
n_chars_remain = HUGE(1)
endif
read_loop : do
if(n_chars_remain <= 0) return
n_chars_read = MIN(n_chars_remain, GET_BUFFER_LEN)
if(PRESENT(iostat)) then
read(unit, FMT='(A)', ADVANCE='NO', IOSTAT=iostat, SIZE=n_chars_read) buffer(:n_chars_read)
if(iostat < 0) exit read_loop
if(iostat > 0) return
else
read(unit, FMT='(A)', ADVANCE='NO', EOR=999, SIZE=n_chars_read) buffer(:n_chars_read)
endif
string = string//buffer(:n_chars_read)
n_chars_remain = n_chars_remain - n_chars_read
end do read_loop
999 continue
string = string//buffer(:n_chars_read)
! Finish (end-of-record)
return
end subroutine get_unit
!| Read from the default unit into a varying string,
! with a custom varying-string separator
!
subroutine get_set_VS (string, set, separator, maxlen, iostat)
type(varying_string), intent(out) :: string
type(varying_string), intent(in) :: set
type(varying_string), intent(out), optional :: separator
integer, intent(in), optional :: maxlen
integer, intent(out), optional :: iostat
call get(string, char(set), separator, maxlen, iostat)
! Finish
return
end subroutine get_set_VS
!| Read from the default unit into a varying string,
! with a custom character-string separator
!
subroutine get_set_CH (string, set, separator, maxlen, iostat)
type(varying_string), intent(out) :: string
character(LEN=*), intent(in) :: set
type(varying_string), intent(out), optional :: separator
integer, intent(in), optional :: maxlen
integer, intent(out), optional :: iostat
integer :: n_chars_remain
character(LEN=1) :: buffer
integer :: i_set
string = ''
if(PRESENT(maxlen)) then
n_chars_remain = maxlen
else
n_chars_remain = HUGE(1)
endif
if(PRESENT(separator)) separator = ''
read_loop : do
if(n_chars_remain <= 0) return
if(PRESENT(iostat)) then
read(*, FMT='(A1)', ADVANCE='NO', IOSTAT=iostat) buffer
if(iostat /= 0) exit read_loop
else
read(*, FMT='(A1)', ADVANCE='NO', EOR=999) buffer
endif
i_set = SCAN(buffer, set)
if(i_set == 1) then
if(PRESENT(separator)) separator = buffer
exit read_loop
endif
string = string//buffer
n_chars_remain = n_chars_remain - 1
end do read_loop
999 continue
! Finish
return
end subroutine get_set_CH
!| Read from the specified unit into a varying string,
! with a custom varying-string separator
!
subroutine get_unit_set_VS (unit, string, set, separator, maxlen, iostat)
integer, intent(in) :: unit
type(varying_string), intent(out) :: string
type(varying_string), intent(in) :: set
type(varying_string), intent(out), optional :: separator
integer, intent(in), optional :: maxlen
integer, intent(out), optional :: iostat
call get(unit, string, char(set), separator, maxlen, iostat)
! Finish
return
end subroutine get_unit_set_VS
!| Read from the default unit into a varying string,
! with a custom character-string separator
!
subroutine get_unit_set_CH (unit, string, set, separator, maxlen, iostat)
integer, intent(in) :: unit
type(varying_string), intent(out) :: string
character(LEN=*), intent(in) :: set
type(varying_string), intent(out), optional :: separator
integer, intent(in), optional :: maxlen
integer, intent(out), optional :: iostat
integer :: n_chars_remain
character(LEN=1) :: buffer
integer :: i_set
string = ''
if(PRESENT(maxlen)) then
n_chars_remain = maxlen
else
n_chars_remain = HUGE(1)
endif
if(PRESENT(separator)) separator = ''
read_loop : do
if(n_chars_remain <= 0) return
if(PRESENT(iostat)) then
read(unit, FMT='(A1)', ADVANCE='NO', IOSTAT=iostat) buffer
if(iostat /= 0) exit read_loop
else
read(unit, FMT='(A1)', ADVANCE='NO', EOR=999) buffer
endif
i_set = SCAN(buffer, set)
if(i_set == 1) then
if(PRESENT(separator)) separator = buffer
exit read_loop
endif
string = string//buffer
n_chars_remain = n_chars_remain - 1
end do read_loop
999 continue
! Finish
return
end subroutine get_unit_set_CH
!| Append a varying string to the current record of
! the default unit
!
subroutine put_VS (string, iostat)
type(varying_string), intent(in) :: string
integer, intent(out), optional :: iostat
call put(char(string), iostat)
! Finish
end subroutine put_VS
!| Append a character string to the current record of
! the default unit
!
subroutine put_CH (string, iostat)
character(LEN=*), intent(in) :: string
integer, intent(out), optional :: iostat
if(PRESENT(iostat)) then
write(*, FMT='(A)', ADVANCE='NO', IOSTAT=iostat) string
else
write(*, FMT='(A)', ADVANCE='NO') string
endif
! Finish
end subroutine put_CH
!| Append a varying string to the current record of
! the specified unit
!
subroutine put_unit_VS (unit, string, iostat)
integer, intent(in) :: unit
type(varying_string), intent(in) :: string
integer, intent(out), optional :: iostat
call put(unit, char(string), iostat)
! Finish
return
end subroutine put_unit_VS
!| Append a character string to the current record of
! the specified unit
!
subroutine put_unit_CH (unit, string, iostat)
integer, intent(in) :: unit
character(LEN=*), intent(in) :: string
integer, intent(out), optional :: iostat
if(PRESENT(iostat)) then
write(unit, FMT='(A)', ADVANCE='NO', IOSTAT=iostat) string
else
write(unit, FMT='(A)', ADVANCE='NO') string
endif
! Finish
return
end subroutine put_unit_CH
!| Append a varying string to the current record of
! the default unit, terminating the record
!
subroutine put_line_VS (string, iostat)
type(varying_string), intent(in) :: string
integer, intent(out), optional :: iostat
call put_line(char(string), iostat)
! Finish
return
end subroutine put_line_VS
!| Append a varying string to the current record of
! the default unit, terminating the record
!
subroutine put_line_CH (string, iostat)
character(LEN=*), intent(in) :: string
integer, intent(out), optional :: iostat
if(PRESENT(iostat)) then
write(*, FMT='(A,/)', ADVANCE='NO', IOSTAT=iostat) string
else
write(*, FMT='(A,/)', ADVANCE='NO') string
endif
! Finish
return
end subroutine put_line_CH
!| Append a varying string to the current record of
! the specified unit, terminating the record
!
subroutine put_line_unit_VS (unit, string, iostat)
integer, intent(in) :: unit
type(varying_string), intent(in) :: string
integer, intent(out), optional :: iostat
call put_line(unit, char(string), iostat)
! Finish
return
end subroutine put_line_unit_VS
!| Append a varying string to the current record of
! the specified unit, terminating the record
!
subroutine put_line_unit_CH (unit, string, iostat)
integer, intent(in) :: unit
character(LEN=*), intent(in) :: string
integer, intent(out), optional :: iostat
if(PRESENT(iostat)) then
write(unit, FMT='(A,/)', ADVANCE='NO', IOSTAT=iostat) string
else
write(unit, FMT='(A,/)', ADVANCE='NO') string
endif
! Finish
return
end subroutine put_line_unit_CH
!| Extract a varying substring from a varying string
!
elemental function extract_VS (string, start, finish) result (ext_string)
type(varying_string), intent(in) :: string
integer, intent(in), optional :: start
integer, intent(in), optional :: finish
type(varying_string) :: ext_string
ext_string = extract(char(string), start, finish)
! Finish
return
end function extract_VS
!| Extract a varying substring from a character string
!
elemental function extract_CH (string, start, finish) result (ext_string)
character(LEN=*), intent(in) :: string
integer, intent(in), optional :: start
integer, intent(in), optional :: finish
type(varying_string) :: ext_string
integer :: start_
integer :: finish_
if(PRESENT(start)) then
start_ = MAX(1, start)
else
start_ = 1
endif
if(PRESENT(finish)) then
finish_ = MIN(LEN(string), finish)
else
finish_ = LEN(string)
endif
ext_string = var_str(string(start_:finish_))
! Finish
return
end function extract_CH
!| Insert a varying substring into a varying string
!
elemental function insert_VS_VS (string, start, substring) result (ins_string)
type(varying_string), intent(in) :: string
integer, intent(in) :: start
type(varying_string), intent(in) :: substring
type(varying_string) :: ins_string
ins_string = insert(char(string), start, char(substring))
! Finish
return
end function insert_VS_VS
!| Insert a varying substring into a character string
!
elemental function insert_CH_VS (string, start, substring) result (ins_string)
character(LEN=*), intent(in) :: string
integer, intent(in) :: start
type(varying_string), intent(in) :: substring
type(varying_string) :: ins_string
ins_string = insert(string, start, char(substring))
! Finish
return
end function insert_CH_VS
!| Insert a character substring into a varying string
!
elemental function insert_VS_CH (string, start, substring) result (ins_string)
type(varying_string), intent(in) :: string
integer, intent(in) :: start
character(LEN=*), intent(in) :: substring
type(varying_string) :: ins_string
ins_string = insert(char(string), start, substring)
! Finish
return
end function insert_VS_CH
!| Insert a character substring into a character string
!
elemental function insert_CH_CH (string, start, substring) result (ins_string)
character(LEN=*), intent(in) :: string
integer, intent(in) :: start
character(LEN=*), intent(in) :: substring
type(varying_string) :: ins_string
integer :: start_
start_ = MAX(1, MIN(start, LEN(string)+1))
ins_string = var_str(string(:start_-1)//substring//string(start_:))
! Finish
return
end function insert_CH_CH
!| Remove a substring from a varying string
!
elemental function remove_VS (string, start, finish) result (rem_string)
type(varying_string), intent(in) :: string
integer, intent(in), optional :: start
integer, intent(in), optional :: finish
type(varying_string) :: rem_string
rem_string = remove(char(string), start, finish)
! Finish
return
end function remove_VS
!| Remove a substring from a character string
!
elemental function remove_CH (string, start, finish) result (rem_string)
character(LEN=*), intent(in) :: string
integer, intent(in), optional :: start
integer, intent(in), optional :: finish
type(varying_string) :: rem_string
integer :: start_
integer :: finish_
if(PRESENT(start)) then
start_ = MAX(1, start)
else
start_ = 1
endif
if(PRESENT(finish)) then
finish_ = MIN(LEN(string), finish)
else
finish_ = LEN(string)
endif
if(finish_ >= start_) then
rem_string = var_str(string(:start_-1)//string(finish_+1:))
else
rem_string = string
endif
! Finish
return
end function remove_CH
!| Replace part of a varying string with a varying substring
!
elemental function replace_VS_VS_auto (string, start, substring) result (rep_string)
type(varying_string), intent(in) :: string
integer, intent(in) :: start
type(varying_string), intent(in) :: substring
type(varying_string) :: rep_string
rep_string = replace(char(string), start, MAX(start, 1)+len(substring)-1, char(substring))
! Finish
return
end function replace_VS_VS_auto
!| Replace part of a character string with a varying substring
!
elemental function replace_CH_VS_auto (string, start, substring) result (rep_string)
character(LEN=*), intent(in) :: string
integer, intent(in) :: start
type(varying_string), intent(in) :: substring
type(varying_string) :: rep_string
rep_string = replace(string, start, MAX(start, 1)+len(substring)-1, char(substring))
! Finish
return
end function replace_CH_VS_auto
!| Replace part of a varying string with a character substring
!
elemental function replace_VS_CH_auto (string, start, substring) result (rep_string)
type(varying_string), intent(in) :: string
integer, intent(in) :: start
character(LEN=*), intent(in) :: substring
type(varying_string) :: rep_string
rep_string = replace(char(string), start, MAX(start, 1)+LEN(substring)-1, substring)
! Finish
return
end function replace_VS_CH_auto
!| Replace part of a character string with a character substring
!
elemental function replace_CH_CH_auto (string, start, substring) result (rep_string)
character(LEN=*), intent(in) :: string
integer, intent(in) :: start
character(LEN=*), intent(in) :: substring
type(varying_string) :: rep_string
rep_string = replace(string, start, MAX(start, 1)+LEN(substring)-1, substring)
! Finish
return
end function replace_CH_CH_auto
!| Replace part of a varying string with a varying substring
!
elemental function replace_VS_VS_fixed (string, start, finish, substring) result (rep_string)
type(varying_string), intent(in) :: string
integer, intent(in) :: start
integer, intent(in) :: finish
type(varying_string), intent(in) :: substring
type(varying_string) :: rep_string
rep_string = replace(char(string), start, finish, char(substring))
! Finish
return
end function replace_VS_VS_fixed
!| Replace part of a character string with a varying substring
!
elemental function replace_CH_VS_fixed (string, start, finish, substring) result (rep_string)
character(LEN=*), intent(in) :: string
integer, intent(in) :: start
integer, intent(in) :: finish
type(varying_string), intent(in) :: substring
type(varying_string) :: rep_string
rep_string = replace(string, start, finish, char(substring))
! Finish
return
end function replace_CH_VS_fixed
!| Replace part of a varying string with a character substring
!
elemental function replace_VS_CH_fixed (string, start, finish, substring) result (rep_string)
type(varying_string), intent(in) :: string
integer, intent(in) :: start
integer, intent(in) :: finish
character(LEN=*), intent(in) :: substring
type(varying_string) :: rep_string
rep_string = replace(char(string), start, finish, substring)
! Finish
return
end function replace_VS_CH_fixed
!| Replace part of a character string with a character substring
!
elemental function replace_CH_CH_fixed (string, start, finish, substring) result (rep_string)
character(LEN=*), intent(in) :: string
integer, intent(in) :: start
integer, intent(in) :: finish
character(LEN=*), intent(in) :: substring
type(varying_string) :: rep_string
integer :: start_
integer :: finish_
start_ = MAX(1, start)
finish_ = MIN(LEN(string), finish)
if(finish_ < start_) then
rep_string = insert(string, start_, substring)
else
rep_string = var_str(string(:start_-1)//substring//string(finish_+1:))
endif
! Finish
return
end function replace_CH_CH_fixed
!| Replace part of a varying string with a varying
! substring, at a location matching a varying-
! string target
!
elemental function replace_VS_VS_VS_target (string, target, substring, every, back) result (rep_string)
type(varying_string), intent(in) :: string
type(varying_string), intent(in) :: target
type(varying_string), intent(in) :: substring
logical, intent(in), optional :: every
logical, intent(in), optional :: back
type(varying_string) :: rep_string
rep_string = replace(char(string), char(target), char(substring), every, back)
! Finish
return
end function replace_VS_VS_VS_target
!| Replace part of a character string with a varying
! substring, at a location matching a varying-
! string target
!
elemental function replace_CH_VS_VS_target (string, target, substring, every, back) result (rep_string)
character(LEN=*), intent(in) :: string
type(varying_string), intent(in) :: target
type(varying_string), intent(in) :: substring
logical, intent(in), optional :: every
logical, intent(in), optional :: back
type(varying_string) :: rep_string
rep_string = replace(string, char(target), char(substring), every, back)
! Finish
return
end function replace_CH_VS_VS_target
!| Replace part of a character string with a varying
! substring, at a location matching a character-
! string target
!
elemental function replace_VS_CH_VS_target (string, target, substring, every, back) result (rep_string)
type(varying_string), intent(in) :: string
character(LEN=*), intent(in) :: target
type(varying_string), intent(in) :: substring
logical, intent(in), optional :: every
logical, intent(in), optional :: back
type(varying_string) :: rep_string
rep_string = replace(char(string), target, char(substring), every, back)
! Finish
return
end function replace_VS_CH_VS_target
!| Replace part of a character string with a varying
! substring, at a location matching a character-
! string target
!
elemental function replace_CH_CH_VS_target (string, target, substring, every, back) result (rep_string)
character(LEN=*), intent(in) :: string
character(LEN=*), intent(in) :: target
type(varying_string), intent(in) :: substring
logical, intent(in), optional :: every
logical, intent(in), optional :: back
type(varying_string) :: rep_string
rep_string = replace(string, target, char(substring), every, back)
! Finish
return
end function replace_CH_CH_VS_target
!| Replace part of a varying string with a character
! substring, at a location matching a varying-
! string target
!
elemental function replace_VS_VS_CH_target (string, target, substring, every, back) result (rep_string)
type(varying_string), intent(in) :: string
type(varying_string), intent(in) :: target
character(LEN=*), intent(in) :: substring
logical, intent(in), optional :: every
logical, intent(in), optional :: back
type(varying_string) :: rep_string
rep_string = replace(char(string), char(target), substring, every, back)
! Finish
return
end function replace_VS_VS_CH_target
!| Replace part of a character string with a character
! substring, at a location matching a varying-
! string target
!
elemental function replace_CH_VS_CH_target (string, target, substring, every, back) result (rep_string)
character(LEN=*), intent(in) :: string
type(varying_string), intent(in) :: target
character(LEN=*), intent(in) :: substring
logical, intent(in), optional :: every
logical, intent(in), optional :: back
type(varying_string) :: rep_string
rep_string = replace(string, char(target), substring, every, back)
! Finish
return
end function replace_CH_VS_CH_target
!| Replace part of a varying string with a character
! substring, at a location matching a character-
! string target
!
elemental function replace_VS_CH_CH_target (string, target, substring, every, back) result (rep_string)
type(varying_string), intent(in) :: string
character(LEN=*), intent(in) :: target
character(LEN=*), intent(in) :: substring
logical, intent(in), optional :: every
logical, intent(in), optional :: back
type(varying_string) :: rep_string
rep_string = replace(char(string), target, substring, every, back)
! Finish
return
end function replace_VS_CH_CH_target
!| Handle special cases when LEN(target) == 0. Such
! instances are prohibited by the standard, but
! since this function is elemental, no error can be
! thrown. Therefore, it makes sense to handle them
! in a sensible manner
!
elemental function replace_CH_CH_CH_target (string, target, substring, every, back) result (rep_string)
character(LEN=*), intent(in) :: string
character(LEN=*), intent(in) :: target
character(LEN=*), intent(in) :: substring
logical, intent(in), optional :: every
logical, intent(in), optional :: back
type(varying_string) :: rep_string
logical :: every_
logical :: back_
type(varying_string) :: work_string
integer :: length_target
integer :: i_target
if(LEN(target) == 0) then
if(LEN(string) /= 0) then
rep_string = string
else
rep_string = substring
endif
return
end if
! Replace part of a character string with a character
! substring, at a location matching a character-
! string target
if(PRESENT(every)) then
every_ = every
else
every_ = .false.
endif
if(PRESENT(back)) then
back_ = back
else
back_ = .false.
endif
rep_string = ''
work_string = string
length_target = LEN(target)
replace_loop : do
i_target = index(work_string, target, back_)
if(i_target == 0) exit replace_loop
if(back_) then
rep_string = substring//extract(work_string, start=i_target+length_target)//rep_string
work_string = extract(work_string, finish=i_target-1)
else
rep_string = rep_string//extract(work_string, finish=i_target-1)//substring
work_string = extract(work_string, start=i_target+length_target)
endif
if(.NOT. every_) exit replace_loop
end do replace_loop
if(back_) then
rep_string = work_string//rep_string
else
rep_string = rep_string//work_string
endif
! Finish
return
end function replace_CH_CH_CH_target
!| Split a varying string into two verying strings
!
elemental subroutine split_VS (string, word, set, separator, back)
type(varying_string), intent(inout) :: string
type(varying_string), intent(out) :: word
type(varying_string), intent(in) :: set
type(varying_string), intent(out), optional :: separator
logical, intent(in), optional :: back
call split_CH(string, word, char(set), separator, back)
! Finish
return
end subroutine split_VS
!| Split a varying string into two verying strings
!
elemental subroutine split_CH (string, word, set, separator, back)
type(varying_string), intent(inout) :: string
type(varying_string), intent(out) :: word
character(LEN=*), intent(in) :: set
type(varying_string), intent(out), optional :: separator
logical, intent(in), optional :: back
logical :: back_
integer :: i_separator
if(PRESENT(back)) then
back_ = back
else
back_ = .false.
endif
i_separator = scan(string, set, back_)
if(i_separator /= 0) then
if(back_) then
word = extract(string, start=i_separator+1)
if(PRESENT(separator)) separator = extract(string, start=i_separator, finish=i_separator)
string = extract(string, finish=i_separator-1)
else
word = extract(string, finish=i_separator-1)
if(PRESENT(separator)) separator = extract(string, start=i_separator, finish=i_separator)
string = extract(string, start=i_separator+1)
endif
else
word = string
if(PRESENT(separator)) separator = ''
string = ''
endif
! Finish
return
end subroutine split_CH
end module iso_varying_string