split_lines Subroutine

public pure subroutine split_lines(text, lines, nlines)

Split input text into lines based on CR, LF, or CRLF line endings Trailing newlines do not create empty lines

Arguments

Type IntentOptional Attributes Name
character(len=*), intent(in) :: text
character(len=:), intent(out), allocatable :: lines(:)
integer, intent(out) :: nlines

Called by

proc~~split_lines~~CalledByGraph proc~split_lines split_lines proc~read_xyz_string read_xyz_string proc~read_xyz_string->proc~split_lines proc~read_xyz_file read_xyz_file proc~read_xyz_file->proc~read_xyz_string proc~initialize_system_geometry initialize_system_geometry proc~initialize_system_geometry->proc~read_xyz_file

Variables

Type Visibility Attributes Name Initial
integer, private :: i
integer, private :: line_end
integer, private :: line_start
integer, private :: max_line_len
character(len=:), private, allocatable :: temp_lines(:)

Source Code

   pure subroutine split_lines(text, lines, nlines)
      !! Split input text into lines based on CR, LF, or CRLF line endings
      !! Trailing newlines do not create empty lines
      character(len=*), intent(in) :: text
      character(len=:), allocatable, intent(out) :: lines(:)
      integer, intent(out) :: nlines

      integer :: i, line_start, line_end, max_line_len
      character(len=:), allocatable :: temp_lines(:)

      if (len(text) == 0) then
         nlines = 0
         allocate (character(len=1) :: lines(0))
         return
      end if

      ! Pass 1: Count lines and find maximum line length
      nlines = 0
      max_line_len = 0
      line_start = 1
      i = 1

      do while (i <= len(text))
         ! Check for line ending
         if (text(i:i) == achar(13)) then  ! CR
            ! Check for CRLF
            if (i < len(text) .and. text(i + 1:i + 1) == achar(10)) then
               line_end = i - 1
               i = i + 2  ! Skip both CR and LF
            else
               line_end = i - 1
               i = i + 1
            end if
            nlines = nlines + 1
            max_line_len = max(max_line_len, line_end - line_start + 1)
            line_start = i
         else if (text(i:i) == achar(10)) then  ! LF
            line_end = i - 1
            nlines = nlines + 1
            max_line_len = max(max_line_len, line_end - line_start + 1)
            i = i + 1
            line_start = i
         else
            i = i + 1
         end if
      end do

      ! Handle last line if text doesn't end with newline
      if (line_start <= len(text)) then
         nlines = nlines + 1
         max_line_len = max(max_line_len, len(text) - line_start + 1)
      end if

      ! Handle empty text or ensure at least length 1
      if (max_line_len == 0) max_line_len = 1

      ! Allocate output array
      allocate (character(len=max_line_len) :: temp_lines(nlines))

      ! Pass 2: Extract lines
      nlines = 0
      line_start = 1
      i = 1

      do while (i <= len(text))
         ! Check for line ending
         if (text(i:i) == achar(13)) then  ! CR
            ! Check for CRLF
            if (i < len(text) .and. text(i + 1:i + 1) == achar(10)) then
               line_end = i - 1
               i = i + 2
            else
               line_end = i - 1
               i = i + 1
            end if
            nlines = nlines + 1
            temp_lines(nlines) = ""  ! Initialize line before copying
            if (line_end >= line_start) then
               ! Intel compiler workaround: use character-by-character copy
               block
                  integer :: j, line_len
                  line_len = line_end - line_start + 1
                  do j = 1, line_len
                     temp_lines(nlines) (j:j) = text(line_start + j - 1:line_start + j - 1)
                  end do
               end block
            end if
            line_start = i
         else if (text(i:i) == achar(10)) then  ! LF
            line_end = i - 1
            nlines = nlines + 1
            temp_lines(nlines) = ""  ! Initialize line before copying
            if (line_end >= line_start) then
               ! Intel compiler workaround: use character-by-character copy
               block
                  integer :: j, line_len
                  line_len = line_end - line_start + 1
                  do j = 1, line_len
                     temp_lines(nlines) (j:j) = text(line_start + j - 1:line_start + j - 1)
                  end do
               end block
            end if
            i = i + 1
            line_start = i
         else
            i = i + 1
         end if
      end do

      ! Handle last line if text doesn't end with newline
      if (line_start <= len(text)) then
         nlines = nlines + 1
         temp_lines(nlines) = ""  ! Initialize line before copying
         ! Intel compiler workaround: use character-by-character copy
         block
            integer :: j, line_len
            line_len = len(text) - line_start + 1
            do j = 1, line_len
               temp_lines(nlines) (j:j) = text(line_start + j - 1:line_start + j - 1)
            end do
         end block
      end if

      ! Copy to output (use explicit loop for Intel compiler compatibility)
      allocate (character(len=max_line_len) :: lines(nlines))
      block
         integer :: iline
         do iline = 1, nlines
            lines(iline) = temp_lines(iline)
         end do
      end block

   end subroutine split_lines