-
-
Save ComingNine/4010199758d1e976b0c8 to your computer and use it in GitHub Desktop.
Fortran version of Delphi's TStringList.f90
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
module Classes_TStringList | |
use System | |
implicit none | |
private | |
public :: TStringListItem, TStringList | |
type :: TStringListItem | |
character(len=:), pointer :: PString => null () | |
class(*), pointer :: PObject => null () | |
end type | |
type :: TStringList | |
private | |
type(TStringListItem), dimension(:), pointer :: PList => null () | |
integer(kind=I8) :: FCount = 0 | |
integer(kind=I8) :: FCapacity = 0 | |
logical :: FSorted = .false. | |
logical :: FCaseSensitive = .true. | |
logical :: FDuplicateAllowed = .true. | |
integer(kind=I1) :: FDefined = 0 | |
character(len=1) :: FDelimiter | |
character(len=:), allocatable :: FLineBreak | |
character(len=1) :: FQuoteChar | |
character(len=1) :: FNameValueSeparator | |
contains | |
private | |
final :: DestroyStringList | |
final :: DestroyStringLists | |
procedure, pass :: ExchangeItems | |
procedure, pass :: Grow | |
procedure, pass :: QuickSort | |
procedure, pass :: SetCapacity | |
procedure, pass :: CompareStrings | |
procedure, pass :: InsertItem | |
procedure, pass, public :: SetTextStr | |
procedure, pass, public :: SetDelimitedText | |
procedure, pass, public :: GetDelimiter | |
procedure, pass, public :: SetDelimiter | |
procedure, pass, public :: GetLineBreak | |
procedure, pass, public :: SetLineBreak | |
procedure, pass, public :: GetQuoteChar | |
procedure, pass, public :: SetQuoteChar | |
procedure, pass, public :: GetNameValueSeparator | |
procedure, pass, public :: SetNameValueSeparator | |
procedure, pass, public :: GetCount | |
procedure, pass, public :: IsSorted | |
procedure, pass, public :: SetSorted | |
procedure, pass, public :: IsCaseSensitive | |
procedure, pass, public :: SetCaseSensitive | |
procedure, pass, public :: IsDuplicateAllowed | |
procedure, pass, public :: SetDuplicateAllowed | |
procedure, pass, public :: GetString | |
procedure, pass, public :: SetString | |
procedure, pass, public :: GetObject | |
procedure, pass, public :: SetObject | |
procedure, pass, public :: Add | |
procedure, pass, public :: AddObject | |
procedure, pass, public :: Clear | |
procedure, pass, public :: Delete | |
procedure, pass, public :: Exchange | |
procedure, pass, public :: Find | |
procedure, pass, public :: IndexOf | |
procedure, pass, public :: Insert | |
procedure, pass, public :: InsertObject | |
procedure, pass, public :: Sort | |
procedure, pass, public :: CustomSort | |
procedure, pass, public :: LoadFromFile | |
procedure, pass, public :: SaveToFile | |
end type TStringList | |
interface | |
function TStringListSortCompare(List, Index1, Index2) | |
use System | |
import TStringList | |
implicit none | |
integer :: TStringListSortCompare | |
type(TStringList), intent(in) :: List | |
integer(kind=I8), intent(in) :: Index1 | |
integer(kind=I8), intent(in) :: Index2 | |
end function TStringListSortCompare | |
end interface | |
contains | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
function StringListCompareStrings (List, Index1, Index2) | |
integer :: StringListCompareStrings | |
type(TStringList), intent(in) :: List | |
integer(kind=I8), intent(in) :: Index1 | |
integer(kind=I8), intent(in) :: Index2 | |
StringListCompareStrings = List%CompareStrings(List%PList(Index1)%PString, List%PList(Index2)%PString) | |
end function StringListCompareStrings | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
subroutine DestroyStringList (this) | |
type(TStringList), intent(inout) :: this | |
write (*,*) '[INFO] TStringList.DestroyStringList: ' | |
call this%Clear | |
end subroutine DestroyStringList | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
subroutine DestroyStringLists (this) | |
type(TStringList), dimension(:), intent(inout) :: this | |
integer(kind=I8) :: I | |
write (*,*) '[INFO] TStringList.DestroyStringLists: ' | |
do I = 1, Size(this) | |
call this(I)%Clear | |
end do | |
end subroutine DestroyStringLists | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
subroutine ExchangeItems (this, Index1, Index2) | |
class(TStringList), intent(inout) :: this | |
integer(kind=I8) :: Index1 | |
integer(kind=I8) :: Index2 | |
character(len=:), pointer :: TempPStr | |
class(*), pointer :: TempPObj | |
TempPStr => this%PList(Index1)%PString | |
this%PList(Index1)%PString => this%PList(Index2)%PString | |
this%PList(Index2)%PString => TempPStr | |
TempPObj => this%PList(Index1)%PObject | |
this%PList(Index1)%PObject => this%PList(Index2)%PObject | |
this%PList(Index2)%PObject => TempPObj | |
end subroutine ExchangeItems | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
subroutine Grow (this) | |
class(TStringList), intent(inout) :: this | |
integer(kind=I8) :: Delta | |
Delta = 0 | |
select case (this%FCapacity) | |
case (:8) | |
Delta = 4 | |
case (9:64) | |
Delta = 16 | |
case (65:) | |
Delta = this%FCapacity / 4 | |
end select | |
call this%SetCapacity(this%FCapacity + Delta) | |
end subroutine Grow | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
recursive subroutine QuickSort (this, L, R, SCompare) | |
class(TStringList), intent(inout) :: this | |
integer, intent(inout) :: L | |
integer, intent(in) :: R | |
procedure(TStringListSortCompare) :: SCompare | |
integer :: I | |
integer :: J | |
integer :: P | |
do | |
I = L | |
J = R | |
P = ISHFT (L + R, -1) | |
do | |
do | |
if (SCompare(this, I, P) >= 0) then | |
exit | |
else | |
I = I + 1 | |
end if | |
end do | |
do | |
if (SCompare(this, J, P) <= 0) then | |
exit | |
else | |
J = J - 1 | |
end if | |
end do | |
if (I <= J) then | |
if (I /= J) call this%ExchangeItems(I, J) | |
if (P == I) then | |
P = J | |
else if (P == J) then | |
P = I | |
end if | |
I = I + 1 | |
J = J - 1 | |
end if | |
if (I > J) exit | |
end do | |
if (L < J) call this%QuickSort(L, J, SCompare) | |
L = I | |
if (I >= R) exit | |
end do | |
end subroutine QuickSort | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
subroutine SetCapacity (this, newCapacity) | |
class(TStringList), intent(inout) :: this | |
integer(kind=I8), intent(in) :: newCapacity | |
type(TStringListItem), dimension(:), pointer :: oldPList | |
integer(kind=I8) :: I | |
nullify (oldPList) | |
if ((newCapacity < this%FCount) .or. (newCapacity > MAX_LIST_SIZE)) then | |
write (*,*) '[ERROR] TStringList.SetCapacity: INVALID newCapacity!' | |
return | |
end if | |
if (newCapacity == this%FCapacity) then | |
return | |
else if (newCapacity > this%FCapacity) then | |
if (this%FCapacity == 0) then | |
allocate (this%PList(newCapacity)) | |
else | |
oldPList => this%PList | |
allocate (this%PList(newCapacity)) | |
do I = 1, Size(oldPList) | |
this%PList(I)%PString => oldPList(I)%PString | |
this%PList(I)%PObject => oldPList(I)%PObject | |
end do | |
deallocate (oldPList) | |
end if | |
else if (newCapacity < this%FCapacity) then | |
if (newCapacity == 0) then | |
deallocate(this%PList) | |
else | |
write (*,*) '[ERROR] TStringList.SetCapacity: UNEXPECTED newCapacity!' | |
return | |
end if | |
end if | |
this%FCapacity = newCapacity | |
end subroutine SetCapacity | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
function CompareStrings (this, String1, String2) | |
use SysUtils | |
implicit none | |
integer :: CompareStrings | |
class(TStringList), intent(in) :: this | |
character(len=*), intent(in) :: String1 | |
character(len=*), intent(in) :: String2 | |
character(len=:), allocatable :: UString1 | |
character(len=:), allocatable :: UString2 | |
if (this%FCaseSensitive) then | |
if (String1 == String2) then | |
CompareStrings = 0 | |
else if (String1 < String2) then | |
CompareStrings = -1 | |
else | |
CompareStrings = 1 | |
end if | |
else | |
UString1 = UpperCase (String1) | |
UString2 = UpperCase (String2) | |
if (UString1 == UString2) then | |
CompareStrings = 0 | |
else if (UString1 < UString2) then | |
CompareStrings = -1 | |
else | |
CompareStrings = 1 | |
end if | |
end if | |
end function CompareStrings | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
subroutine InsertItem (this, Index, S, AObject) | |
class(TStringList), intent(inout) :: this | |
integer(kind=I8), intent(in) :: Index | |
character(len=*), intent(in) :: S | |
class(*), pointer :: AObject | |
integer :: I | |
if (this%FCount == this%FCapacity) call this%Grow() | |
if (Index <= this%FCount) then | |
do I = this%FCount, Index, -1 | |
this%PList(I + 1) = this%PList(I) | |
end do | |
end if | |
allocate (CHARACTER(LEN=LEN(S)) :: this%PList(Index)%PString) | |
this%PList(Index)%PString = S | |
this%PList(Index)%PObject => AObject | |
this%FCount = this%FCount + 1 | |
end subroutine InsertItem | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
subroutine SetTextStr (this, S) | |
use system | |
implicit none | |
class(TStringList), intent(inout) :: this | |
character(len=*), intent(in) :: S | |
integer(kind=i8) :: lenStr | |
integer(kind=i8) :: I | |
integer(kind=i8) :: J | |
integer(kind=i8) :: strIndex | |
call this%Clear(); | |
lenStr = len(S) | |
I = 1 | |
J = 1 | |
do | |
if (I > lenStr) exit | |
if (S(I:I) == NUL) then | |
exit | |
else | |
J = I | |
do | |
if (I > lenStr) exit | |
if ((S(I:I) == NUL) .or. (S(I:I) == this%FDelimiter)) then | |
exit | |
else | |
I = I + 1 | |
end if | |
end do | |
strIndex = this%Add(S(J:I-1)) | |
if (I > lenStr) exit | |
if (S(I:I) == this%FDelimiter) then | |
I = I + 1 | |
if (I > lenStr) exit | |
if (S(I:I) == NUL) then | |
strIndex = this%Add('') | |
end if | |
end if | |
end if | |
end do | |
end subroutine SetTextStr | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
subroutine SetDelimitedText (this, S) | |
use system | |
implicit none | |
class(TStringList), intent(inout) :: this | |
character(len=*), intent(in) :: S | |
integer(kind=i8) :: lenStr | |
integer(kind=i8) :: I | |
integer(kind=i8) :: J | |
integer(kind=i8) :: strIndex | |
call this%Clear(); | |
lenStr = len(S) | |
I = 1 | |
J = 1 | |
do | |
if (I > lenStr) exit | |
if (S(I:I) == NUL) then | |
exit | |
else | |
J = I | |
do | |
if (I > lenStr) exit | |
if ((S(I:I) == NUL) .or. (S(I:I) == this%FDelimiter)) then | |
exit | |
else | |
I = I + 1 | |
end if | |
end do | |
strIndex = this%Add(S(J:I-1)) | |
if (I > lenStr) exit | |
if (S(I:I) == this%FDelimiter) then | |
I = I + 1 | |
if (I > lenStr) exit | |
if (S(I:I) == NUL) then | |
strIndex = this%Add('') | |
end if | |
end if | |
end if | |
end do | |
end subroutine SetDelimitedText | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
function GetDelimiter (this) | |
character(len=1) :: GetDelimiter | |
class(TStringList), intent(inout) :: this | |
if (.not. BTEST(this%FDefined, 0)) call this%SetDelimiter (',') | |
GetDelimiter = this%FDelimiter | |
end function GetDelimiter | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
subroutine SetDelimiter (this, Delimiter) | |
class(TStringList), intent(inout) :: this | |
character(len=1), intent(in) :: Delimiter | |
if ((this%FDelimiter /= Delimiter) .or. (.not. BTEST(this%FDefined, 0))) then | |
this%FDefined = IBSET(this%FDefined, 0) | |
this%FDelimiter = Delimiter | |
end if | |
end subroutine SetDelimiter | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
function GetLineBreak (this) | |
character(len=:), allocatable :: GetLineBreak | |
class(TStringList), intent(inout) :: this | |
if (.not. BTEST(this%FDefined, 1)) call this%SetLineBreak (sLineBreak) | |
GetLineBreak = this%FLineBreak | |
end function GetLineBreak | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
subroutine SetLineBreak (this, LineBreak) | |
class(TStringList), intent(inout) :: this | |
character(len=*), intent(in) :: LineBreak | |
if (.not. ALLOCATED (this%FLineBreak)) then | |
this%FDefined = IBSET(this%FDefined, 1) | |
this%FLineBreak = LineBreak | |
else if ((this%FLineBreak /= LineBreak) .or. (.not. BTEST(this%FDefined, 1))) then | |
this%FDefined = IBSET(this%FDefined, 1) | |
this%FLineBreak = LineBreak | |
end if | |
end subroutine SetLineBreak | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
function GetQuoteChar (this) | |
character(len=1) :: GetQuoteChar | |
class(TStringList), intent(inout) :: this | |
if (.not. BTEST(this%FDefined, 2)) call this%SetQuoteChar ('"') | |
GetQuoteChar = this%FQuoteChar | |
end function GetQuoteChar | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
subroutine SetQuoteChar (this, QuoteChar) | |
class(TStringList), intent(inout) :: this | |
character(len=1), intent(in) :: QuoteChar | |
if ((this%FQuoteChar /= QuoteChar) .or. (.not. BTEST(this%FDefined, 2))) then | |
this%FDefined = IBSET(this%FDefined, 2) | |
this%FQuoteChar = QuoteChar | |
end if | |
end subroutine SetQuoteChar | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
function GetNameValueSeparator (this) | |
character(len=1) :: GetNameValueSeparator | |
class(TStringList), intent(inout) :: this | |
if (.not. BTEST(this%FDefined, 3)) call this%SetNameValueSeparator ('=') | |
GetNameValueSeparator = this%FNameValueSeparator | |
end function GetNameValueSeparator | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
subroutine SetNameValueSeparator (this, NameValueSeparator) | |
class(TStringList), intent(inout) :: this | |
character(len=1), intent(in) :: NameValueSeparator | |
if ((this%FNameValueSeparator /= NameValueSeparator) .or. (.not. BTEST(this%FDefined, 3))) then | |
this%FDefined = IBSET(this%FDefined, 3) | |
this%FNameValueSeparator = NameValueSeparator | |
end if | |
end subroutine SetNameValueSeparator | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
function GetCount (this) | |
integer(kind=I8) :: GetCount | |
class(TStringList), intent(in) :: this | |
GetCount = this%FCount | |
end function GetCount | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
function IsSorted (this) | |
logical :: IsSorted | |
class(TStringList), intent(in) :: this | |
IsSorted = this%FSorted | |
end function IsSorted | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
subroutine SetSorted (this, Sorted) | |
class(TStringList), intent(inout) :: this | |
logical, intent(in) :: Sorted | |
if (this%FSorted /= Sorted) then | |
if (Sorted) call this%Sort | |
this%FSorted = Sorted | |
end if | |
end subroutine SetSorted | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
function IsCaseSensitive (this) | |
logical :: IsCaseSensitive | |
class(TStringList), intent(in) :: this | |
IsCaseSensitive = this%FCaseSensitive | |
end function IsCaseSensitive | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
subroutine SetCaseSensitive (this, CaseSensitive) | |
class(TStringList), intent(inout) :: this | |
logical, intent(in) :: CaseSensitive | |
this%FCaseSensitive = CaseSensitive | |
end subroutine SetCaseSensitive | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
function IsDuplicateAllowed (this) | |
logical :: IsDuplicateAllowed | |
class(TStringList), intent(in) :: this | |
IsDuplicateAllowed = this%FDuplicateAllowed | |
end function IsDuplicateAllowed | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
subroutine SetDuplicateAllowed (this, DuplicateAllowed) | |
class(TStringList), intent(inout) :: this | |
logical, intent(in) :: DuplicateAllowed | |
this%FDuplicateAllowed = DuplicateAllowed | |
end subroutine SetDuplicateAllowed | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
function GetString (this, Index) | |
character(len=:), allocatable :: GetString | |
class(TStringList), intent(in) :: this | |
integer, intent(in) :: Index | |
if ((Index < 1) .or. (Index > this%FCount)) then | |
write (*,'(A, I4)') '[ERROR] TStringList.GetString: List index out of bounds ', Index | |
return | |
end if | |
GetString = this%PList(Index)%PString | |
end function GetString | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
subroutine SetString (this, Index, S) | |
class(TStringList), intent(inout) :: this | |
integer, intent(in) :: Index | |
character(len=*), intent(in) :: S | |
if (this%FSorted) then | |
write (*,*) '[ERROR] TStringList.SetString: Operation not allowed on sorted list' | |
return | |
end if | |
if ((Index < 1) .or. (Index > this%FCount)) then | |
write (*,'(A, I4)') '[ERROR] TStringList.SetString: List index out of bounds ', Index | |
return | |
end if | |
deallocate (this%PList(Index)%PString) | |
allocate (CHARACTER(LEN=LEN(S)) :: this%PList(Index)%PString) | |
this%PList(Index)%PString = S | |
end subroutine SetString | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
function GetObject (this, Index) | |
class(*), pointer :: GetObject | |
class(TStringList), intent(in) :: this | |
integer, intent(in) :: Index | |
if ((Index < 1) .or. (Index > this%FCount)) then | |
write (*,'(A, I4)') '[ERROR] TStringList.GetObject: List index out of bounds ', Index | |
return | |
end if | |
GetObject => this%PList(Index)%PObject | |
end function GetObject | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
subroutine SetObject (this, Index, AObject) | |
class(TStringList), intent(inout) :: this | |
integer, intent(in) :: Index | |
class(*), pointer :: AObject | |
if (this%FSorted) then | |
write (*,*) '[ERROR] TStringList.SetObject: Operation not allowed on sorted list' | |
return | |
end if | |
if ((Index < 1) .or. (Index > this%FCount)) then | |
write (*,'(A, I4)') '[ERROR] TStringList.SetObject: List index out of bounds ', Index | |
return | |
end if | |
this%PList(Index)%PObject => AObject | |
end subroutine SetObject | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
function Add (this, S) | |
integer(kind=I8) :: Add | |
class(TStringList), intent(inout) :: this | |
character(len=*), intent(in) :: S | |
class(*), pointer :: AObject | |
AObject => null () | |
ADD = this%AddObject (S, AObject) | |
end function Add | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
function AddObject (this, S, AObject) | |
integer(kind=I8) :: AddObject | |
class(TStringList), intent(inout) :: this | |
character(len=*), intent(in) :: S | |
class(*), pointer :: AObject | |
if (.not. this%FSorted) then | |
AddObject = this%FCount + 1 | |
else | |
if (this%Find(S, AddObject)) then | |
if (.not. this%FDuplicateAllowed) return | |
end if | |
end if | |
call this%InsertItem (AddObject, S, AObject) | |
end function AddObject | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
subroutine Clear (this) | |
class(TStringList), intent(inout) :: this | |
integer(kind=I8) :: I | |
do I = 1, this%FCount | |
deallocate (this%PList(I)%PString) | |
end do | |
this%FCount = 0 | |
call this%SetCapacity (0) | |
end subroutine Clear | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
subroutine Delete (this, Index) | |
class(TStringList), intent(inout) :: this | |
integer(kind=I8), intent(in) :: Index | |
integer(kind=I8) :: I | |
if ((Index < 1) .or. (Index > this%FCount)) then | |
write (*,'(A, I4)') '[ERROR] TStringList.Delete: List index out of bounds ', Index | |
return | |
end if | |
deallocate (this%PList(Index)%PString) | |
if (Index < this%FCount) then | |
do I = Index, this%FCount | |
this%PList(I) = this%PList(I + 1) | |
end do | |
end if | |
this%FCount = this%FCount - 1 | |
end subroutine Delete | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
subroutine Exchange (this, Index1, Index2) | |
class(TStringList), intent(inout) :: this | |
integer(kind=I8), intent(in) :: Index1 | |
integer(kind=I8), intent(in) :: Index2 | |
if ((Index1 < 1) .or. (Index1 > this%FCount)) then | |
write (*,'(A, I4)') '[ERROR] TStringList.Exchange: List index out of bounds ', Index1 | |
return | |
end if | |
if ((Index2 < 1) .or. (Index2 > this%FCount)) then | |
write (*,'(A, I4)') '[ERROR] TStringList.Exchange: List index out of bounds ', Index2 | |
return | |
end if | |
call this%ExchangeItems (Index1, Index2) | |
end subroutine Exchange | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
function Find (this, S, Index) | |
logical :: Find | |
class(TStringList), intent(in) :: this | |
character(len=*), intent(in) :: S | |
integer(kind=I8), intent(out) :: Index | |
integer :: L | |
integer :: H | |
integer :: I | |
integer :: C | |
Find = .false. | |
L = 1 | |
H = this%FCount | |
do | |
if (L > H) exit | |
I = ISHFT(L + H, -1) | |
C = this%CompareStrings (this%PList(I)%PString, S) | |
if (C < 0) then | |
L = I + 1 | |
else | |
H = I - 1 | |
if (C == 0) then | |
Find = .true. | |
if (.not. this%FDuplicateAllowed) L = I | |
end if | |
end if | |
end do | |
Index = L | |
end function Find | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
function IndexOf (this, S) | |
integer(kind=I8) :: IndexOf | |
class(TStringList), intent(in) :: this | |
character(len=*), intent(in) :: S | |
if (.not. this%FSorted) then | |
do IndexOf = 1, this%FCount | |
if (this%CompareStrings(this%PList(IndexOf)%PString, S) == 0) return | |
end do | |
IndexOf = -1 | |
else | |
if (.not. this%Find(S, IndexOf)) IndexOf = -1 | |
end if | |
end function IndexOf | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
subroutine Insert (this, Index, S) | |
class(TStringList), intent(inout) :: this | |
integer(kind=I8), intent(in) :: Index | |
character(len=*), intent(in) :: S | |
class(*), pointer :: AObject | |
AObject => null () | |
call this%InsertObject (Index, S, AObject) | |
end subroutine Insert | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
subroutine InsertObject (this, Index, S, AObject) | |
class(TStringList), intent(inout) :: this | |
integer(kind=I8), intent(in) :: Index | |
character(len=*), intent(in) :: S | |
class(*), pointer :: AObject | |
if (this%FSorted) then | |
write (*,*) '[ERROR] TStringList.InsertObject: Operation not allowed on sorted list' | |
return | |
end if | |
if ((Index < 1) .or. (Index > this%FCount)) then | |
write (*,'(A, I4)') '[ERROR] TStringList.InsertObject: List index out of bounds ', Index | |
return | |
end if | |
call this%InsertItem(Index, S, AObject) | |
end subroutine InsertObject | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
subroutine Sort (this) | |
class(TStringList), intent(inout) :: this | |
call this%CustomSort(StringListCompareStrings) | |
end subroutine Sort | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
subroutine CustomSort (this, Compare) | |
class(TStringList), intent(inout) :: this | |
procedure(TStringListSortCompare) :: Compare | |
integer(kind=I8) :: L | |
integer(kind=I8) :: R | |
L = 1 | |
R = this%FCount | |
if ((.not. this%FSorted) .and. (this%FCount > 1)) then | |
call this%QuickSort(L, R, Compare) | |
end if | |
end subroutine CustomSort | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
subroutine LoadFromFile (this, FilePathName) | |
use System | |
implicit none | |
class(TStringList), intent(inout) :: this | |
character(len=*), intent(in) :: FilePathName | |
integer :: FCLX_FILEIO | |
integer :: iErr | |
character(len=256) :: msgErr | |
integer(kind=I8) :: fileSize | |
character(len=:), pointer :: pBuffer | |
integer(kind=I8) :: I | |
integer(kind=I8) :: J | |
integer(kind=I8) :: strIndex | |
nullify (pBuffer) | |
FCLX_FILEIO = GetThreadFileIO() | |
open (unit=FCLX_FILEIO, file=FilePathName, status='unknown', access='stream', form='unformatted', iostat=iErr, iomsg=msgErr) | |
if (iErr == 0) then | |
inquire (unit=FCLX_FILEIO, size=fileSize) | |
allocate (CHARACTER(LEN=fileSize+1) :: pBuffer) | |
pBuffer(fileSize+1:fileSize+1)=NUL | |
read (unit=FCLX_FILEIO) pBuffer(:fileSize) | |
close (unit=FCLX_FILEIO) | |
I = 1 | |
do | |
select case (pBuffer(I:I)) | |
case (NUL) | |
exit | |
case default | |
J = I | |
do | |
select case (pBuffer(I:I)) | |
case (NUL, CR, LF) | |
exit | |
case default | |
I = I + 1 | |
end select | |
end do | |
strIndex = this%Add(pBuffer(J:I-1)) | |
if (pBuffer(I:I) == CR) I = I + 1 | |
if (pBuffer(I:I) == LF) I = I + 1 | |
end select | |
end do | |
deallocate (pBuffer) | |
else | |
write (*,*) '[ERROR]TStringList.LoadFromFile: ' | |
write (*,*) 'msgErr is ' // msgErr | |
return | |
end if | |
end subroutine LoadFromFile | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** | |
subroutine SaveToFile (this, FilePathName) | |
use System | |
implicit none | |
class(TStringList), intent(inout) :: this | |
character(len=*), intent(in) :: FilePathName | |
integer :: FCLX_FILEIO | |
integer :: iErr | |
character(len=256) :: msgErr | |
integer(kind=I8) :: fileSize | |
character(len=:), pointer :: pBuffer | |
integer(kind=I8) :: I | |
integer(kind=I8) :: Count | |
character(len=:), allocatable :: LB | |
integer(kind=I8) :: lenS | |
integer(kind=I8) :: lenLB | |
integer(kind=I8) :: idxBuffer | |
nullify (pBuffer) | |
Count = this%GetCount() | |
fileSize = 0 | |
LB = this%GetLineBreak() | |
lenLB = LEN(LB) | |
do I = 1, Count | |
lenS = LEN(this%PList(I)%PString) | |
fileSize = fileSize + lenS + lenLB | |
end do | |
allocate (CHARACTER(LEN=fileSize+1) :: pBuffer) | |
pBuffer(fileSize+1:fileSize+1)=NUL | |
idxBuffer = 1 | |
do I = 1, Count | |
lenS = LEN(this%PList(I)%PString) | |
if (lenS > 0) then | |
pBuffer(idxBuffer:idxBuffer+lenS) = this%PList(I)%PString | |
idxBuffer = idxBuffer + lenS | |
end if | |
if (lenLB > 0) then | |
pBuffer(idxBuffer:idxBuffer+lenLB) = LB | |
idxBuffer = idxBuffer + lenLB | |
end if | |
end do | |
FCLX_FILEIO = GetThreadFileIO() | |
open (unit=FCLX_FILEIO, file=FilePathName, status='unknown', access='stream', form='unformatted', iostat=iErr, iomsg=msgErr) | |
if (iErr == 0) then | |
write (unit=FCLX_FILEIO) pBuffer(:fileSize) | |
close (unit=FCLX_FILEIO) | |
else | |
write (*,*) '[ERROR]TStringList.SaveToFile: ' | |
write (*,*) 'msgErr is ' // msgErr | |
return | |
end if | |
deallocate (pBuffer) | |
end subroutine SaveToFile | |
end module Classes_TStringList | |
!***|****1****|****2****|****3****|****4****|****5****|****6****|****7** |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment