! utils.f90 ! general utilities for Fortran programs ! Author: Albert Huang for SSAI/NASA GSFC GMAO module ncdw_strarrutils implicit none contains function lentrim(s) character(len=*) :: s integer lentrim do lentrim = len(s), 1, -1 if (s(lentrim:lentrim) .ne. ' ') return end do end function lentrim function string_count_substr(s, substr) result(sub_count) character(len=*), intent(in) :: s character(len=*), intent(in) :: substr integer :: sub_count integer :: substr_len, i, jump substr_len = len(substr) sub_count = 0 jump = 1 i = 1 do while (i <= len(s) - len(substr)) if (s(i:i+len(substr)-1) == substr) then sub_count = sub_count + 1 jump = len(substr) else jump = 1 end if i = i + jump end do end function string_count_substr function string_get_max_split(s, substr) result(max_len) character(len=*), intent(in) :: s character(len=*), intent(in) :: substr integer :: sub_count integer :: substr_len, i, jump integer :: max_len, tmp_len substr_len = len(substr) sub_count = 0 jump = 1 i = 1 tmp_len = 0 max_len = 0 do while (i <= len_trim(s) - len(substr) + 1) if (s(i:i+len(substr)-1) == substr) then sub_count = sub_count + 1 if (tmp_len > max_len) max_len = tmp_len tmp_len = 0 jump = len(substr) else jump = 1 tmp_len = tmp_len + 1 end if i = i + jump end do ! Do one more check to ensure we get the end! if ((tmp_len + len(substr) - 1) > max_len) max_len = tmp_len + len(substr) - 1 end function string_get_max_split function string_split_index(s, delimiter) result(split_strings) character(len=*) :: s character(len=*) :: delimiter integer :: substr_len, i, jump integer :: tmp_idx, start_idx, total integer :: split_length, item_length character(len=:), allocatable :: split_strings(:) character(len=:), allocatable :: tmp_str ! Get lengths split_length = string_count_substr(s, delimiter) + 1 item_length = string_get_max_split(s, delimiter) allocate(character(item_length) :: split_strings(split_length)) allocate(character(item_length) :: tmp_str) substr_len = len(delimiter) jump = 1 i = 1 tmp_idx = 1 start_idx = 1 total = 1 do while (i <= len_trim(s) - len(delimiter) + 1) if (s(i:i+len(delimiter)-1) == delimiter) then if (start_idx /= tmp_idx) then split_strings(total) = s(start_idx:tmp_idx - 1) else split_strings(total) = "" end if tmp_idx = tmp_idx + len(delimiter) start_idx = tmp_idx total = total + 1 jump = len(delimiter) else jump = 1 tmp_idx = tmp_idx + 1 end if i = i + jump end do ! Do one more check to ensure we get the end! split_strings(total) = s(start_idx:tmp_idx - 1) end function string_split_index ! asl = assumed shape length subroutine string_array_dump(strings) character(len=:), allocatable :: strings(:) integer i write (*, "(A, I0)") "Length of strings array: ", size(strings(:)) print *, " -> String array dump:" do i = 1, size(strings(:)) if (strings(i) == "") then write (*, "(A, I0, A, I0, A, I0, A)") " --> Position ", i, ": (empty) [Trim length = ", len_trim(strings(i)), ", Full length = ", len(strings(i)), "]" else write (*, "(A, I0, A, A, A, I0, A, I0, A)") " --> Position ", i, ": '", trim(strings(i)), "' [Trim length = ", len_trim(strings(i)), ", Full length = ", len(strings(i)), "]" end if end do end subroutine string_array_dump function max_len_string_array(str_arr, arr_length) result(max_len) character(len=*), intent(in) :: str_arr(:) integer , intent(in) :: arr_length integer :: i, max_len max_len = -1 #ifdef _DEBUG_MEM_ write (*, "(A, I0)") " ** max_len_string_array: size(str_arr) is ", size(str_arr) #endif do i = 1, arr_length if (len_trim(str_arr(i)) > max_len) max_len = len_trim(str_arr(i)) #ifdef _DEBUG_MEM_ write (*, "(A, I0, A, I0)") "max_len_string_array: str_arr(", i, ") is " // trim(str_arr(i)) // ", size is ", len_trim(str_arr(i)) write (*, "(A, I0)") "max_len_string_array: max_len is ", max_len #endif end do end function max_len_string_array function max_len_notrim_string_array(str_arr, arr_length) result(max_len) character(len=*), intent(in) :: str_arr(:) integer , intent(in) :: arr_length integer :: i, max_len max_len = -1 #ifdef _DEBUG_MEM_ write (*, "(A, I0)") " ** max_len_notrim_string_array: size(str_arr) is ", size(str_arr) #endif do i = 1, arr_length if (len(str_arr(i)) > max_len) max_len = len(str_arr(i)) #ifdef _DEBUG_MEM_ write (*, "(A, I0, A, I0)") "max_len_notrim_string_array: str_arr(", i, ") is " // trim(str_arr(i)) // ", size is ", len_trim(str_arr(i)) write (*, "(A, I0)") "max_len_notrim_string_array: max_len is ", max_len #endif end do end function max_len_notrim_string_array subroutine string_before_delimiter(s, delimiter, string_part) character(len=*), intent(in) :: s character(len=*), intent(in) :: delimiter character(len=:), intent(inout), allocatable :: string_part integer :: substr_len, i, jump integer :: tmp_idx, start_idx, total logical found found = .FALSE. ! Get lengths substr_len = len(delimiter) jump = 1 i = 1 tmp_idx = 1 start_idx = 1 total = 1 do while (i <= len_trim(s) - len(delimiter) + 1) if (s(i:i+len(delimiter)-1) == delimiter) then found = .TRUE. exit else jump = 1 tmp_idx = tmp_idx + 1 end if i = i + jump end do ! Do one more check to ensure we get the end! if (found) then if (start_idx == tmp_idx) then allocate(character(0) :: string_part) string_part = "" else allocate(character(tmp_idx - start_idx + 1) :: string_part) string_part = s(start_idx:tmp_idx - 1) end if else allocate(character(len(s)) :: string_part) string_part = s end if end subroutine string_before_delimiter end module ncdw_strarrutils