Split input text into lines based on CR, LF, or CRLF line endings Trailing newlines do not create empty lines
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| character(len=*), | intent(in) | :: | text | |||
| character(len=:), | intent(out), | allocatable | :: | lines(:) | ||
| integer, | intent(out) | :: | nlines |
| 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(:) |
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