@@ -62,7 +62,8 @@ contains |
| 62 | ! After --, everything is a file/pattern argument | 62 | ! After --, everything is a file/pattern argument |
| 63 | if (end_of_options) then | 63 | if (end_of_options) then |
| 64 | if (.not. has_explicit_pattern .and. size(patterns) == 0) then | 64 | if (.not. has_explicit_pattern .and. size(patterns) == 0) then |
| 65 | - call append_pattern(patterns, trim(arg)) | 65 | + ! Use exact length from get_command_argument to preserve whitespace patterns |
| | 66 | + call append_pattern(patterns, arg(1:arg_len)) |
| 66 | has_explicit_pattern = .true. | 67 | has_explicit_pattern = .true. |
| 67 | else | 68 | else |
| 68 | call append_file(files, trim(arg)) | 69 | call append_file(files, trim(arg)) |
@@ -96,7 +97,8 @@ contains |
| 96 | else | 97 | else |
| 97 | ! Non-option argument | 98 | ! Non-option argument |
| 98 | if (.not. has_explicit_pattern .and. size(patterns) == 0) then | 99 | if (.not. has_explicit_pattern .and. size(patterns) == 0) then |
| 99 | - call append_pattern(patterns, trim(arg)) | 100 | + ! Use exact length from get_command_argument to preserve whitespace patterns |
| | 101 | + call append_pattern(patterns, arg(1:arg_len)) |
| 100 | has_explicit_pattern = .true. | 102 | has_explicit_pattern = .true. |
| 101 | else | 103 | else |
| 102 | call append_file(files, trim(arg)) | 104 | call append_file(files, trim(arg)) |
@@ -687,41 +689,87 @@ contains |
| 687 | end subroutine handle_option_argument | 689 | end subroutine handle_option_argument |
| 688 | | 690 | |
| 689 | subroutine read_patterns_from_file(patterns, filename, ierr) | 691 | subroutine read_patterns_from_file(patterns, filename, ierr) |
| | 692 | + !> Read patterns from file, preserving exact line lengths (including whitespace-only lines) |
| 690 | character(len=max_pattern_len), allocatable, intent(inout) :: patterns(:) | 693 | character(len=max_pattern_len), allocatable, intent(inout) :: patterns(:) |
| 691 | character(len=*), intent(in) :: filename | 694 | character(len=*), intent(in) :: filename |
| 692 | integer, intent(out) :: ierr | 695 | integer, intent(out) :: ierr |
| 693 | | 696 | |
| 694 | - integer :: unit_num, ios | 697 | + integer :: unit_num, ios, line_len |
| 695 | character(len=max_pattern_len) :: line | 698 | character(len=max_pattern_len) :: line |
| | 699 | + character(len=1) :: ch |
| 696 | | 700 | |
| 697 | ierr = 0 | 701 | ierr = 0 |
| 698 | - open(newunit=unit_num, file=filename, status='old', action='read', iostat=ios) | 702 | + ! Use stream access to read exact line lengths (preserving whitespace patterns) |
| | 703 | + open(newunit=unit_num, file=filename, status='old', action='read', & |
| | 704 | + access='stream', form='formatted', iostat=ios) |
| 699 | if (ios /= 0) then | 705 | if (ios /= 0) then |
| 700 | write(error_unit, '(A)') 'ferp: ' // trim(filename) // ': No such file or directory' | 706 | write(error_unit, '(A)') 'ferp: ' // trim(filename) // ': No such file or directory' |
| 701 | ierr = 2 | 707 | ierr = 2 |
| 702 | return | 708 | return |
| 703 | end if | 709 | end if |
| 704 | | 710 | |
| | 711 | + line_len = 0 |
| | 712 | + line = '' |
| | 713 | + |
| 705 | do | 714 | do |
| 706 | - read(unit_num, '(A)', iostat=ios) line | 715 | + read(unit_num, '(A1)', iostat=ios, advance='no') ch |
| 707 | - if (ios /= 0) exit | 716 | + if (ios /= 0) then |
| 708 | - call append_pattern(patterns, trim(line)) | 717 | + ! EOF or error - save current line if non-empty |
| | 718 | + if (line_len > 0) then |
| | 719 | + call append_pattern(patterns, line(1:line_len)) |
| | 720 | + end if |
| | 721 | + exit |
| | 722 | + end if |
| | 723 | + |
| | 724 | + if (ch == char(10)) then |
| | 725 | + ! Newline - save pattern with exact length (even if zero for empty lines) |
| | 726 | + if (line_len > 0) then |
| | 727 | + call append_pattern(patterns, line(1:line_len)) |
| | 728 | + else |
| | 729 | + ! Empty line - skip (grep ignores empty pattern lines) |
| | 730 | + end if |
| | 731 | + line_len = 0 |
| | 732 | + line = '' |
| | 733 | + else if (ch == char(13)) then |
| | 734 | + ! Carriage return - ignore (handle Windows line endings) |
| | 735 | + else |
| | 736 | + ! Regular character - add to line |
| | 737 | + if (line_len < max_pattern_len) then |
| | 738 | + line_len = line_len + 1 |
| | 739 | + line(line_len:line_len) = ch |
| | 740 | + end if |
| | 741 | + end if |
| 709 | end do | 742 | end do |
| 710 | | 743 | |
| 711 | close(unit_num) | 744 | close(unit_num) |
| 712 | end subroutine read_patterns_from_file | 745 | end subroutine read_patterns_from_file |
| 713 | | 746 | |
| 714 | subroutine append_pattern(patterns, pattern) | 747 | subroutine append_pattern(patterns, pattern) |
| | 748 | + !> Append a pattern to the patterns array, preserving its exact length |
| | 749 | + !> Uses null terminator to mark the true end of the pattern |
| 715 | character(len=max_pattern_len), allocatable, intent(inout) :: patterns(:) | 750 | character(len=max_pattern_len), allocatable, intent(inout) :: patterns(:) |
| 716 | character(len=*), intent(in) :: pattern | 751 | character(len=*), intent(in) :: pattern |
| 717 | | 752 | |
| 718 | character(len=max_pattern_len), allocatable :: temp(:) | 753 | character(len=max_pattern_len), allocatable :: temp(:) |
| 719 | - integer :: n | 754 | + integer :: n, plen |
| 720 | | 755 | |
| 721 | n = size(patterns) | 756 | n = size(patterns) |
| 722 | allocate(temp(n + 1)) | 757 | allocate(temp(n + 1)) |
| 723 | if (n > 0) temp(1:n) = patterns | 758 | if (n > 0) temp(1:n) = patterns |
| 724 | - temp(n + 1) = pattern | 759 | + |
| | 760 | + ! Store pattern with null terminator to preserve exact length |
| | 761 | + plen = len(pattern) |
| | 762 | + if (plen > 0 .and. plen < max_pattern_len) then |
| | 763 | + temp(n + 1) = pattern |
| | 764 | + temp(n + 1)(plen + 1:plen + 1) = char(0) ! Null terminator |
| | 765 | + else if (plen == 0) then |
| | 766 | + ! Empty pattern - store just null terminator |
| | 767 | + temp(n + 1) = char(0) |
| | 768 | + else |
| | 769 | + ! Pattern too long - truncate |
| | 770 | + temp(n + 1) = pattern(1:max_pattern_len) |
| | 771 | + end if |
| | 772 | + |
| 725 | call move_alloc(temp, patterns) | 773 | call move_alloc(temp, patterns) |
| 726 | end subroutine append_pattern | 774 | end subroutine append_pattern |
| 727 | | 775 | |